1. 分类
2. 7种内排序算法的各种指标
排序方法 |
平均情况 |
最好情况 |
最坏情况 |
辅助空间 |
稳定性 |
移动次数的平均情况 |
移动次数的最好情况 |
移动次数的最坏情况 |
冒泡排序 |
O(n2) |
O(n) |
O(n2) |
O(1) |
稳定 |
O(n2) |
0 |
O(n2) |
简单选择排序 |
O(n2) |
O(n2) |
O(n2) |
O(1) |
稳定 |
O(n) |
0 |
O(n) |
直接插入排序 |
O(n2) |
O(n) |
O(n2) |
O(1) |
稳定 |
O(n2) |
O(n) |
O(n2) |
希尔排序 |
O(nlogn)~O(n2) |
O(n1.3) |
O(n2) |
O(1) |
不稳定 |
|
|
|
堆排序 |
O(nlogn) |
O(nlogn) |
O(nlogn) |
O(1) |
不稳定 |
|
|
|
归并排序 |
O(nlogn) |
O(nlogn) |
O(nlogn) |
O(n) |
稳定 |
|
|
|
快速排序 |
O(nlogn) |
O(nlogn) |
O(n2) |
O(logn)~O(n) |
不稳定 |
|
|
|
3. 分析(“>”表示优于)
从平均情况看:
堆排序、归并排序、快速排序 > 希尔排序 > 简单算法
从最好情况看:
冒泡排序、直接插入排序 > 其它算法
从最坏情况看:
堆排序、归并排序 > 其它算法
从空间复杂度看:
简单算法、希尔排序、堆排序 > 快速排序 > 归并排序
从稳定性看:
简单算法、归并排序 > 希尔排序、堆排序、快速排序
从移动次数的平均情况看:
简单选择排序 > 冒泡排序、直接插入排序
从移动次数的最好情况看:
简单选择排序、冒泡排序 > 直接插入排序
从移动次数的最坏情况看:
简单选择排序 > 冒泡排序、直接插入排序
4. 结论
5. 具体实现
冒泡排序
1 /* 对顺序表L作冒泡排序 */ 2 void BubbleSort(SqList *L) 3 { 4 int i,j; 5 for(i = 1; i < L->length; i++) 6 { 7 for(j = L->length - 1; j >= 1; j--) /* 注意j是从后往前循环 */ 8 { 9 if(L->r[j]>L->[j + 1]) /* 若前者大于后者 */ 10 { 11 swap(L, j, j + 1); /* 变换L->r[j]与L->r[j + 1]的值 */ 12 } 13 } 14 } 15 }
1 void BubbleSort(SqList *L) 2 { 3 int i,j; 4 Status flag = TRUE; /* flag用来作为标记 */ 5 for(i = 1; i < L->length && flag; i++) /* 若flag为true则退出循环 */ 6 { 7 flag = FALSE; /* 初始为false */ 8 for(j = L->length - 1; j >= 1; j--) /* 注意j是从后往前循环 */ 9 { 10 if(L->r[j]>L->[j + 1]) /* 若前者大于后者 */ 11 { 12 swap(L, j, j + 1); /* 变换L->r[j]与L->r[j + 1]的值 */ 13 flag = TRUE; /* 如果有数据交换,则flag为true */ 14 } 15 } 16 } 17 }
简单选择排序
1 /* 对顺序表L作简单选择排序 */ 2 void SelectSort(SqList *L) 3 { 4 int i,j,min; 5 for(i = 1; i < L->length; i++) 6 { 7 min = 1; /* 将当前下标定义为最小值下标 */ 8 for(j = i + 1; j <= L->length; j++) /* 循环之后的数据 */ 9 { 10 if(L->r[min] > L->r[j]) /* 如果有小于当前最小值的关键字 */ 11 min = j; /* 将此关键字的下标赋值给min */ 12 } 13 if(i != min) /* 若min不等于i,说明找到最小值,交换 */ 14 swap(L,i,min); /* 变换L->r[i]与L->r[min]的值 */ 15 } 16 }
直接插入排序
1 /* 对顺序表L作直接插入排序 */ 2 void InsertSort(SqList *L) 3 { 4 int i,j; 5 for(i = 2; i <= L->length; i++) 6 { 7 if(L->r[i] < L->r[i - 1]) /* 需将L->r[i]插入有序子表 */ 8 { 9 L->r[0] = L->r[i]; /* 设置哨兵 */ 10 for(j = i - 1; L->r[j] > L->r[0]; j--) 11 L->r[j + 1] = L->r[j]; /* 记录后移 */ 12 L->r[j + 1] = L->r[0]; /* 插入到正确位置 */ 13 } 14 } 15 }
希尔排序
1 /* 对顺序表L作希尔排序 */ 2 void ShellSort(SqList *L) 3 { 4 int i,j; 5 int increment = L->length; 6 do 7 { 8 increment = increment/3 + 1; /* 增量序列 */ 9 for(i = increment + 1; i <= L->length; i++) 10 { 11 if(L->r[i] < L->r[i - increment]) 12 { /* 需将L->r[i]插入有序增量子表 */ 13 L->r[0] = L->r[i]; /* 暂存在L->r[0] */ 14 for(j = i - increment; j > 0 && L->r[0] < L->r[j]; j -= increment) 15 { 16 L->r[j + increment] = L->r[j]; /* 记录后移,查找插入位置 */ 17 L->r[j + increment] = L->r[0]; /* 插入 */ 18 } 19 } 20 } 21 } 22 while(increment > 1); 23 }
堆排序
1 /* 对顺序表L作堆排序 */ 2 void HeapSort(SqList *L) 3 { 4 int i; 5 for(i = L->length / 2; i > 0; i--) /* 把L中的r构建成一个大顶堆 */ 6 HeapAdjust(L,i,L->length); 7 8 for(i = L->length; i > 1; i--) 9 { 10 swap(L,1,i); /* 将堆顶记录和当前未经排序子序列的最后一个记录交换 */ 11 HeapAdjust(L,1,i - 1); /* 将L->r[1..i-1]重新调整为大顶堆 */ 12 } 13 } 14 15 /* 已知L->r[s..m]中记录的关键字除L->r[s]之外均满足堆的定义 */ 16 /* 本函数调整L->r[s]的关键字,使L->r[s..m]成为一个大顶堆 */ 17 void HeapAdjust(SqList *L, int s, int m) 18 { 19 int temp,j; 20 temp = L->r[s]; 21 for(j = 2 * s; j <= m; j *= 2) /* 沿关键字较大的孩子结点向下筛选 */ 22 { 23 if(j < m && L->r[j] < L->r[j + 1]) 24 ++j; /* j为关键字中较大的记录的下标 */ 25 if(temp >= L->r[j]) 26 break; /* rc应插入在位置s上 */ 27 L->r[s] = L->r[j]; 28 s = j; 29 } 30 L->r[s] = temp; /* 插入 */ 31 }
归并排序
1 /* 对顺序表L作归并排序 */ 2 void MergeSort(SqList *L) 3 { 4 MSort(L->r, L->r, 1, L->length); 5 } 6 7 /* 将SR[s..t]归并排序为TR1[s..t] */ 8 void MSort(int SR[], int TR1[], int s, int t) 9 { 10 int m; 11 int TR2[MAXSIZE + 1]; 12 if(s == t) 13 TR1[s] = SR[s]; 14 else 15 { 16 m = (s + t) / 2; /* 将SR[s..t]平分为SR[s..m]和SR[m+1..t] */ 17 MSort(SR,TR2,s,m); /* 递归将SR[s..m]归并为有序的TR2[s..m] */ 18 MSort(SR,TR2,m+1,t); /* 递归将SR[m+1..t]归并为有序的TR2[m+1..t] */ 19 Merge(TR2,TR1,s,m,t); /* 将TR2[s..m]和TR2[m+1..t]归并到TR1[s..t] */ 20 } 21 } 22 23 /* 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] */ 24 void Merge(int SR[], int TR[], int i, int m, int n) 25 { 26 int j,k,l; 27 for(j = m + 1, k = i; i <= m && j <= n; k++) /* 将SR中记录由小到大归并入TR */ 28 { 29 if(SR[i] < SR[j]) 30 TR[k] = SR[i++]; 31 else 32 TR[k] = SR[j++]; 33 } 34 if(i <= m) 35 { 36 for(l = 0; l <= m - i; l++) 37 TR[k + l] = SR[i + l]; /* 将剩余的SR[i..m]复制到TR */ 38 } 39 if(j <= n) 40 { 41 for(l = 0; l <= n - j; l++) 42 TR[k + l] = SR[j + l]; /* 将剩余的SR[j..n]复制到TR */ 43 } 44 }
1 /* 对顺序表L作归并非递归排序 */ 2 void MergeSort(SqList *L) 3 { 4 int* TR = (int*)malloc(L->length * sizeof(int)); /* 申请额外空间 */ 5 int k = 1; 6 while(k < L->length) 7 { 8 MergePass(L->r, TR, k, L->length); 9 k = 2 * k; /* 子序列长度加倍 */ 10 MergePass(TR, L->r, k, L->length); 11 k = 2 * k; /* 子序列长度加倍 */ 12 } 13 } 14 15 /* 将SR[]中相邻长度为s的子序列两两归并到TR[] */ 16 void MergePass(int SR[], int TR[], int s, int n) 17 { 18 int i = 1; 19 int j; 20 while(i <= n - 2 * s + 1) 21 { 22 Merge(SR,TR,i,i+s-1,i+2*s-1); /* 两两归并 */ 23 i = i + 2 * s; 24 } 25 if(i < n-s+1) /* 归并最后两个序列 */ 26 Merge(SR, TR, i, i+s-1, n); 27 else 28 for(j = i; j <= n; j++) 29 TR[j] = SR[j]; 30 } 31 32 /* 将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] */ 33 void Merge(int SR[], int TR[], int i, int m, int n) 34 { 35 int j,k,l; 36 for(j = m + 1, k = i; i <= m && j <= n; k++) /* 将SR中记录由小到大归并入TR */ 37 { 38 if(SR[i] < SR[j]) 39 TR[k] = SR[i++]; 40 else 41 TR[k] = SR[j++]; 42 } 43 if(i <= m) 44 { 45 for(l = 0; l <= m - i; l++) 46 TR[k + l] = SR[i + l]; /* 将剩余的SR[i..m]复制到TR */ 47 } 48 if(j <= n) 49 { 50 for(l = 0; l <= n - j; l++) 51 TR[k + l] = SR[j + l]; /* 将剩余的SR[j..n]复制到TR */ 52 } 53 }
快速排序
1 /* 对顺序表L作快速排序 */ 2 void QuickSort(SqList *L) 3 { 4 QSort(L, 1, L->length); 5 } 6 7 /* 将顺序表L中的子序列L->r[low..high]作快速排序 */ 8 void QSort(SqList *L, int low, int high) 9 { 10 int pivot; 11 if(low < higt) 12 { 13 pivot = Partition(L,low,high); /* 将L->r[low..high]一分为二,算出枢轴值pivot */ 14 QSort(L,low,pivot-1); /* 对低子表递归排序 */ 15 QSort(L,pivot+1,high); /* 对高子表递归排序 */ 16 } 17 } 18 19 /* 变换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置 */ 20 /* 此时在它之前(后)的记录均不大(小)于它 */ 21 int Partition(SqList *L, int low, int high) 22 { 23 int pivotkey; 24 pivotkey = L->r[low]; /* 用子表的第一个记录作枢轴记录 */ 25 while(low < high) /* 从表的两段交替向中间扫描 */ 26 { 27 while(low < high && L->[high] >= pivotkey) 28 high--; 29 swap(L,low,high); /* 将比枢轴记录小的记录交换到低端 */ 30 while(low < high && L->[low] >= pivotkey) 31 low++; 32 swap(L,low,high); /* 将比枢轴记录大的记录交换到高端 */ 33 } 34 return low; /* 返回枢轴所在位置 */ 35 }
1 /* 优化1:优化选取枢轴,使用三数取中法或九数取中法 */ 2 /* 优化2:优化不必要的交换,采用替换进行操作 */ 3 /* 优化3:优化小数组时的排序方案,长度小时用直接插入排序,长度大时才使用快速排序 */ 4 /* 优化4:优化递归操作,采用迭代的方法代替可以缩减堆栈深度,提高整体性能 */ 5 6 /* 对顺序表L作快速排序 */ 7 void QuickSort(SqList *L) 8 { 9 QSort(L, 1, L->length); 10 } 11 12 #define MAX_LENGTH_INSERT_SORT 7 /* 数组长度阀值 */ 13 /* 将顺序表L中的子序列L->r[low..high]作快速排序 */ 14 void QSort(SqList *L, int low, int high) 15 { 16 int pivot; 17 if((high - low) > MAX_LENGTH_INSERT_SORT) 18 { /* 当high-low大于常数时用快速排序 */ 19 while(low < higt) 20 { 21 pivot = Partition(L,low,high); /* 将L->r[low..high]一分为二,算出枢轴值pivot */ 22 QSort(L,low,pivot-1); /* 对低子表递归排序 */ 23 low = pivot + 1; /* 尾递归 */ 24 } 25 } 26 else /* 当high-low小于等于常数时用直接插入排序 */ 27 InsertSort(L); 28 } 29 30 /* 变换顺序表L中子表的记录,使枢轴记录到位,并返回其所在位置 */ 31 /* 此时在它之前(后)的记录均不大(小)于它 */ 32 int Partition(SqList *L, int low, int high) 33 { 34 int pivotkey; 35 36 /* 优化选取枢轴,使用三数取中法 */ 37 int m = low + (high - low) / 2; /* 计算数组中间的元素的下标 */ 38 if(L->r[low] > L->r[high]) 39 swap(L,low,high); /* 交换左端与右端数据,保证左端较小 */ 40 if(L->r[m] > L->r[high]) 41 swap(L,high,m); /* 交换中间与右端数据,保证中间较小 */ 42 if(L->r[m] > L->r[low]) 43 swap(L,m,low); /* 交换中间与左端数据,保证中间较小 */ 44 /* 此时L.r[low]已经为整个序列左中右三个关键字的中间值 */ 45 46 pivotkey = L->r[low]; /* 用子表的第一个记录作枢轴记录 */ 47 L->r[0] = pivotkey; /* 将枢轴关键字备份到L->r[0] */ 48 while(low < high) /* 从表的两段交替向中间扫描 */ 49 { 50 while(low < high && L->[high] >= pivotkey) 51 high--; 52 L->r[low] = L->r[high]; /* 采用替换而不是交换的方式进行操作 */ 53 while(low < high && L->[low] >= pivotkey) 54 low++; 55 L->r[high] = L->r[low]; /* 采用替换而不是交换的方式进行操作 */ 56 } 57 L->r[low] = L->r[0]; /* 将枢轴数值替换回L.r[low] */ 58 return low; /* 返回枢轴所在位置 */ 59 }