转自:http://www.cnblogs.com/heyonggang/p/3648837.html
从以下几个方面来比较排序算法:
1. 算法的时间和空间复杂度
2. 排序的稳定性
3. 算法结构的复杂度
4. 参加排序的数据规模
排序的稳定性:
稳定排序方法: 插入排序、冒泡排序、二路归并排序、基数排序是稳定排序算法;
不稳定排序方法: 选择排序、谢尔排序、快速排序、堆积排序是不稳定排序算法。
算法复杂度比较:
各种内排序算法的时间、空间复杂度
排序方法
|
平均时间
|
最坏情况
|
辅助空间
|
插入排序
|
O(n*n)
|
O(n*n)
|
O(1)
|
谢尔排序
|
O(n*log2n)
|
O(n*log2n)
|
O(1)
|
泡排序
|
O(n*n)
|
O(n*n)
|
O(1)
|
快速排序
|
O(n*log2n)
|
O(n*n)
|
O(log2n)
|
选择排序
|
O(n*n)
|
O(n*n)
|
O(1)
|
堆积排序
|
O(n*log2n)
|
O(n*log2n)
|
O(1)
|
归并排序
|
O(n*log2n)
|
O(n*log2n)
|
O(n)
|
基数排序
|
O(d*(n+r))
|
O(d*(n+r))
|
O(n+r)
|
有结论如下:
1. 平均情况下,谢尔排序、快速排序、堆积排序、归并排序都能达到较快的排序速度,快速排序最快,堆积排序空间消费最省。
2. 平均情况下,插入排序和泡排序的排序速度较慢,但当参加排序的序列开始就局部有序时,这两种排序算法就能够达到较快的排序速度。最后情况下速度为 O(n), 比情况 1 中叙述的4中方法都好,辅助空间消费也少。所以当 n 较小或者序列开始就局部有序时,可选择这两种方法。
3. 基数排序方法消费的辅助空间较多,但其时间复杂度可简化为O(dn); 当元素的位数较少时,可继续简化为O(n), 这种情况下也能达到较快的排序速度,另外,归并排序需要的辅助空间也较多。
4. 从算法结构的简单性来看,插入排序、泡排序、选择排序比较简单和直接;而谢尔排序、快速排序、堆积排序以及归并排序都可以看做对某一种排序算法的进一步改进,相对而言,改进后的算法都比较复杂。
5. 从参加排序的数据序列的规模大小来看,n越小,采用简单排序方法就越合适;n越大,采用改进的排序方法越合适。这是因为n越小,n*n 与 log2n 的差距越小。
以下是在考虑内排序算法的优缺点后,在某些情况下比较适合的算法选择:
1. 当参加排序的数据规模较大,关键字元素分布比较随机,并且不要求排序稳定性时,宜采用快速排序法。
2. 当参加排序的数据规模较大,内存空间又允许,并且有排序稳定性要求,宜采用归并排序法。
3. 当参加排序的数据规模较大,元素分布可能出现升序或者逆序的情况,并且对排序的稳定性无要求时,宜采用插入排序方法。
4. 当参加排序的数据规模较小(如小于100),元素基本有序(升序),或者分布也比较随机,并且有排序稳定性要求时,宜采用插入排序方法。
5. 当参加排序的数据规模n较小,对排序稳定性又不要求时,宜采用选择排序。
插入排序、选择排序、归并排序都比较容易在链表上实现,当利用链表作为存储结构时,可以避免将大量时间花费在元素的位置移动上。
算法描述:
1. 插入排序:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
void simple_insert(int *data, int len)
-
{
-
if(data == NULL || len < 1)
-
return;
-
-
int temp, i, j;
-
for(i = 1; i < len; ++i) {
-
temp = data[i];
-
j = i - 1;
-
while(j >= 0 && temp < data[j]) {
-
data[j+1] = data[j--];
-
}
-
data[j+1] = temp;
-
}
-
}
-
-
-
-
-
-
-
-
void binary_insert(int *data, int len)
-
{
-
if(data == NULL || len < 1)
-
return;
-
-
int temp, i, j, low, mid, high;
-
for(i = 1; i < len; ++i) {
-
temp = data[i];
-
low = 0;
-
high = i - 1;
-
while(low <= high) {
-
mid = (low + high)/2;
-
if(temp < data[mid])
-
high = mid - 1;
-
else
-
low = mid + 1;
-
}
-
-
for(j = i; j > low; --j)
-
data[j] = data[j-1];
-
-
data[low] = temp;
-
}
-
}
2. 谢尔排序
-
-
-
-
-
-
-
void shellSort(int *data, int len)
-
{
-
if(data == NULL || len < 1)
-
return;
-
-
unsigned int gap = len;
-
int i,j,temp;
-
while(gap > 0) {
-
gap >>= 1;
-
for(i = gap; i < len; ++i) {
-
j = i - gap;
-
temp = data[i];
-
while(j >= 0 && temp < data[j]) {
-
data[j+gap] = data[j];
-
j -= gap;
-
}
-
-
data[j+gap] = temp;
-
}
-
}
-
}
3. 泡排序
-
-
-
-
-
-
-
-
-
-
-
void bubbleSort(int *data, int len)
-
{
-
if(data == NULL || len < 1)
-
return;
-
-
int flag = 1;
-
int i, j, temp;
-
i = len - 1;
-
while(i > 0 && flag == 1) {
-
flag = 0;
-
for(j = 0; j < i; ++j) {
-
if(data[j] > data[j+1]) {
-
temp = data[j];
-
data[j] = data[j+1];
-
data[j+1] = temp;
-
-
flag = 1;
-
}
-
}
-
-
--i;
-
}
-
}
4. 快速排序
-
-
-
-
int randomInRange(int start, int end)
-
{
-
srand(time(NULL));
-
-
return start + rand()%(end-start+1);
-
}
-
-
-
-
-
void swapElem(int *elem1, int *elem2)
-
{
-
int temp = *elem1;
-
*elem1 = *elem2;
-
*elem2 = temp;
-
}
-
-
-
-
-
-
-
int partition(int *data, int len, int start, int end)
-
{
-
if(data == NULL || len < 1 || start < 0 || end >= len) {
-
printf("invalid parameters.");
-
exit(1);
-
}
-
-
int index = randomInRange(start, end);
-
swapElem(&data[index], &data[end]);
-
int small = start - 1;
-
-
for(index = start; index < end; ++index) {
-
if(data[index] < data[end]) {
-
++small;
-
if(small != index)
-
swapElem(&data[index], &data[small]);
-
}
-
}
-
swapElem(&data[++small], &data[end]);
-
-
return small;
-
}
-
-
-
-
-
-
-
-
-
-
void quickSort(int *data, int len, int start, int end)
-
{
-
if(start == end)
-
return;
-
-
int index = partition(data, len, start, end);
-
if(index > start)
-
quickSort(data, len, start, index - 1);
-
if(index < end)
-
quickSort(data, len, index + 1, end);
-
}
5. 选择排序
-
-
-
-
-
-
-
-
-
void selectSort(int *data, int len)
-
{
-
if(data == NULL || len < 1)
-
return;
-
-
int i, j, minIndex;
-
for(i = 0; i < len - 1; ++i) {
-
minIndex = i;
-
j = i + 1;
-
while(j < len) {
-
if(data[j] < data[minIndex])
-
minIndex = j;
-
++j;
-
}
-
-
if(minIndex != i) {
-
int temp = data[i];
-
data[i] = data[minIndex];
-
data[minIndex] = temp;
-
}
-
}
-
}
6. 堆积排序
-
-
-
-
-
-
-
void adjust(int *data, int len, int root)
-
{
-
int temp = data[root];
-
int i = root * 2;
-
-
while(i <= len) {
-
if(i < len && data[i] < data[i + 1])
-
++i;
-
-
if(temp >= data[i])
-
break;
-
-
data[i/2] = data[i];
-
i *= 2;
-
}
-
-
data[i/2] = temp;
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
void heapSort(int *data, int len)
-
{
-
if(data == NULL || len < 1)
-
return;
-
-
int i;
-
for(i = len/2; i > 0; --i) {
-
adjust(data, len, i);
-
}
-
-
int temp;
-
for(i = len; i > 1; --i) {
-
temp = data[1];
-
data[1] = data[i];
-
data[i] = temp;
-
-
adjust(data, i-1, 1);
-
}
-
}
7. 归并排序
-
-
-
-
-
void merge(int *source, int *des, int start, int mid, int end)
-
{
-
int i = start;
-
int j = mid + 1;
-
int k = start;
-
-
while(i <= mid && j <= end) {
-
-
-
-
-
des[k++] = source[i] <= source[j] ? source[i++] : source[j++];
-
}
-
-
while(i <= mid)
-
des[k++] = source[i++];
-
while(j <= end)
-
des[k++] = source[j++];
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
void mpass(int *source, int *des, int len, int t)
-
{
-
int i = 0;
-
if(len - i >= 2*t) {
-
merge(source, des, i, i + t - 1, i + 2 * t - 1);
-
i += 2 * t;
-
}
-
-
if(len - i > t)
-
merge(source, des, i, i + t - 1, len - 1);
-
else {
-
for(; i < len; ++i)
-
des[i] = source[i];
-
}
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
int mergeSort(int *data, int *des, int len)
-
{
-
int flag = -1;
-
if(data == NULL || len < 1)
-
return flag;
-
-
int t = 1;
-
flag = 1;
-
while(t < len) {
-
mpass(data, des, len, t);
-
flag = 0;
-
-
t *= 2;
-
if(t < len) {
-
mpass(des, data, len, t);
-
t *= 2;
-
flag = 1;
-
}
-
}
-
-
return flag;
-
}
8. 基数排序
-
-
-
-
typedef struct Node {
-
int data;
-
struct Node *next;
-
}QLink;
-
-
-
-
-
int maxDig(int *data, int len)
-
{
-
int maxd = 0;
-
int maxCurD = 1;
-
-
int base = 10;
-
for(int i = 0; i < len; ++i) {
-
maxCurD = 1;
-
base = 10;
-
while(data[i] >= base) {
-
++maxCurD;
-
if(maxd < maxCurD)
-
maxd = maxCurD;
-
base *= 10;
-
}
-
}
-
-
return maxd;
-
}
-
-
-
-
-
QLink* transferArrToQLink(int *data, int len)
-
{
-
if(data == NULL || len < 1)
-
return NULL;
-
-
QLink *head = NULL;
-
QLink *rear = NULL;
-
-
for(int i = 0; i < len; ++i) {
-
QLink *cur = (QLink *)malloc(sizeof(QLink));
-
cur->data = data[i];
-
cur->next = NULL;
-
if(head == NULL)
-
head = cur;
-
else
-
rear->next = cur;
-
rear = cur;
-
}
-
-
return head;
-
}
-
-
-
-
-
void freeQLink(QLink *phead)
-
{
-
QLink *toFree = NULL;
-
while(phead != NULL) {
-
toFree = phead;
-
phead = phead->next;
-
free(toFree);
-
}
-
}
-
-
-
-
-
-
int getCurPlaceV(int num, int index)
-
{
-
int placeValue;
-
int i = 0;
-
while(i <= index) {
-
placeValue = num%10;
-
num /= 10;
-
++i;
-
}
-
-
return placeValue;
-
}
-
-
-
-
-
void radixSort(int *data, int len, int radix)
-
{
-
int maxd = maxDig(data, len);
-
printf("maxd = %d\n", maxd);
-
QLink *phead = transferArrToQLink(data, len);
-
-
QLink *Front[radix], *End[radix];
-
QLink *q, *rear;
-
int i, j, curplaceV;
-
for(i = 0; i < maxd; ++i) {
-
printf("the %d times sort\n", i);
-
for(j = 0; j < radix; ++j)
-
Front[j] = End[j] = NULL;
-
-
q = phead;
-
while(q != NULL) {
-
curplaceV = getCurPlaceV(q->data, i);
-
if(Front[curplaceV] == NULL)
-
Front[curplaceV] = q;
-
else
-
End[curplaceV]->next = q;
-
End[curplaceV] = q;
-
-
q = q->next;
-
}
-
-
j = 0;
-
while(Front[j] == NULL)
-
++j;
-
-
phead = Front[j];
-
rear = End[j];
-
++j;
-
for(; j < radix; ++j) {
-
if(Front[j] != NULL) {
-
rear->next = Front[j];
-
rear = End[j];
-
}
-
}
-
rear->next = NULL;
-
}
-
-
q = phead;
-
i = 0;
-
while(q != NULL) {
-
data[i++] = q->data;
-
q = q->next;
-
}
-
-
freeQLink(phead);
-
phead = NULL;
-
}