总述
借图侵删
SHELL排序
时间复杂度:O(N^(X)) (X<=2)
又称“缩小增量排序”,是插入排序的进化版,其高效之处在于通过增量间隔的比较和交换,比朴素的插入排序减少了交换次数,从而提高了效率。感性认知来讲,确实可以提高算法效率,但是我不会证明该算法的时间复杂度。
1 void Shell_sort(int l, int r) 2 { 3 int gap = r - l + 1; 4 int tep = 0; 5 do 6 { 7 gap = gap / 3 + 1; 8 for (int i = l + gap; i <= r; ++i) 9 { 10 if (a[i - gap] > a[i]) 11 { 12 tep = a[i]; 13 int j = i - gap; 14 do 15 { 16 a[j + gap] = a[j]; 17 j -= gap; 18 } while (j >= l && a[j] > tep); 19 a[j + gap] = tep; 20 } 21 } 22 }while (gap > 1); 23 }
归并排序
时间复杂度:O(N*logN)
分治的思想+O(N)合并有序数组。
22 void GB_sort(int l, int r) 23 { 24 if (l == r) return; 25 int mid = (l + r) >> 1; 26 GB_sort(l, mid), GB_sort(mid + 1, r); 27 int t1 = l, t2 = mid + 1, t3 = l; 28 for (int i = l; i <= r; ++i) 29 if ((a[t1] <= a[t2] && t1 <= mid) || t2 == r + 1) b[t3] = a[t1], ++t1, ++t3; 30 else b[t3] = a[t2], ++t2, ++t3; 31 for (int i = l; i <= r; ++i) 32 a[i] = b[i]; 33 }
堆排序
时间复杂度:O(N*logN)
本质上就是维护一个大根堆。也是选择排序的一种。
注意堆的初始化要自下而上!因为update函数是自上而下更新的,向下可以保证操作到位,而向上无法进行。
1 void update(int x, int m) 2 { 3 int t = lson(x); 4 if (t > m) return; 5 if (t < m && a[t + 1] > a[t]) ++t; 6 if (a[t] > a[x]) swap(a[x], a[t]); 7 update(t, m); 8 } 9 10 void HEAP_sort() 11 { 12 for (int i = n; i >= 1; --i) 13 update(i, n); 14 for (int i = n - 1; i >= 1; --i) // 每次取出最大值并维护堆 15 { 16 swap(a[i + 1], a[1]); 17 update(1, i); 18 } 19 }
快速排序
时间复杂度:平均O(N*logN)
交换排序的一种,具体流程如下:
选择基准值---将小于基准值的值置于基准值之前,将大于基准值的值置于基准值之后---递归
不难看出这个算法是很容易被卡成N^2的,故手写时应至少加一个随机化(虽然很少去手写)。
1 void Quick_sort(int l, int r) 2 { 3 if (l >= r) return; 4 int i = l, j = r; 5 int x = a[i]; 6 while (i < j) 7 { 8 while (i < j && a[j] > x) --j; 9 if (i < j) a[i++] = a[j]; 10 while (i < j && a[i] < x) ++i; 11 if (i < j) a[j--] = a[i]; 12 } 13 a[i] = x; 14 Quick_sort(l, i - 1); 15 Quick_sort(i + 1, r); 16 return; 17 }
所以为什么快速排序叫做快排?手写起来惨不忍睹还会被卡