// 直接插入排序 voidinsertSort(ElemType a[], int n){ int i, j; for (int i = 2; i <= n; i++) { if (a[i] < a[i - 1]) { a[0] = a[i]; // a[0]: sentinel for (int j = i - 1; a[j] > a[0]; j--) a[j + 1] = a[j]; // shift right a[j + 1] = a[0]; // insert } } }
method 每次取⼀待排序记录按关键字大小插入到前面已排好序的子序列中, 重复直到完成
时间复杂度:O(n2)
最好情况下比较 0 次、移动 n-1 次,为 O (n);最坏情况下比较∑i=2ni 次、移动∑i=2n(i+1) 次,为O(n2)
空间复杂度:O(1)
稳定:√
适用:顺序和链式存储,链式存储可从前往后依次查找
2. 折半插入排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// 折半插入排序 voidinsertSort(ElemType a[], int n){ int i, j, low, high, mid; for (int i = 2; i <= n; i++) { a[0] = a[i];
low = 1, high = i - 1; while (low <= high) { mid = low + ((high - low) >> 1); if (a[mid] > a[0]) high = mid - 1; else low = mid + 1; } for (j = i - 1; j >= high - 1; --j) { a[j + 1] = a[j]; // shift right } a[high + 1] = a[0]; } }
method 先⽤折半查找找到应该插⼊的位置,再移动元素
时间复杂度:O(n2),分析同上,仅减少了比较元素的次数,约为O(nlog2n)
空间复杂度:O(1)
稳定:√
适用:顺序存储
3. 希尔排序(递减增量排序)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 希尔排序 voidshellSort(ElemType a[], int n){ int dk, i, j; for (dk = n / 2; dk >= 1; dk /= 2) { for (i = dk + 1; i <= n; i++) { if (a[i] < a[i - dk]) { a[0] = a[i]; for (j = i - dk; j > 0 && a[0] < a[j]; j -= dk) a[j + dk] = a[j]; a[j + dk] = a[0]; } } } }
method 先追求表中元素部分有序,再逐渐逼近全局有序
将待排序表分割成 L [i, i + d, i + 2d,…, i + kd] 的 “特殊” 子表,对各个子表直接插⼊排序。缩小增量 d,重复直到 d = 1
时间复杂度:O(n1.3)(n 在某特定范围时)
空间复杂度:O(1)
稳定:×
适用:基本有序的顺序存储
(三)交换排序
1. 冒泡排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 从后往前 voidbubbleSort(ElemType a[], int n){ for (int i = 0; i < n - 1; i++) for (int j = n - 1; j > i; j--) if (a[j - 1] > a[j]) swap(a[j - 1], a[j]); }
// 从前往后 voidbubbleSort2(ElemType a[], int n){ for (int i = 0; i < n - 1; i++) for (int j = 0; j < n - i - 1; j++) if (a[j] > a[j + 1]) swap(a[j], a[j + 1]); }
method 从后往前(或从前往后)两两比较相邻元素的值,若为逆序(即 A [i-1]>A [i]),则交换它们,直到序列比较完
// 快速排序 (in C++) voidquick_sort(int q[], int l, int r){ if (l >= r) { return; } int i = l - 1, j = r + 1, x = q[l + ((r - l) >> 1)]; while (i < j) { do { i++; } while (q[i] < x); do { j--; } while (q[j] > x); if (i < j) { swap(q[i], q[j]); } }
// 快速排序 (in Java) privatestaticvoidquickSort(int l, int r){ if (l >= r) { return; } int x = q[l + ((r - l) >> 1)]; int i = l - 1, j = r + 1; while (i < j) { do { i++; } while (q[i] < x); do { j--; } while (q[j] > x); if (i < j) { swap(i, j); } } quickSort(l, j); quickSort(j + 1, r); }
privatestaticvoidswap(int i, int j){ int t = q[i]; q[i] = q[j]; q[j] = t; }
method
在待排序表 L [1…n] 中任取⼀个元素 pivot 作为枢轴
⼀次划分将待排序表划分为独立的两部分 L [1…k-1] 和 L [k+1…n],使左边所有元素 \textlesspivot,右边所有元素≥ pivot,pivot 放在其最终的位置 L (k) 上
// 选择排序 voidselectSort(ElemType a[], int n){ for (int i = 0; i < n - 1; i++) { int min = a[i]; for (int j = i + 1; j < n; j++) if (a[j] < a[min]) min = j; if (min != i) swap(a[i], a[min]); } }
// 建立大根堆 voidbuildMaxHeap(ElemType a[], int len){ for (int i = len / 2; i > 0; i--) { heapAdjust(a, i, len); } }
// 将以k为根的子树调整为大根堆 voidheapAdjust(ElemType a[], int k, int len){ a[0] = a[k]; for (int i = 2 * k; i <= len; i *= 2) { if (i < len && a[i] < a[i + 1]) i++; if (a[0] >= a[i]) break; else { a[k] = a[i]; k = i; } } a[k] = a[0]; }
// 堆排序 voidheapSort(ElemType a[], int len){ buildMaxHeap(a, len); for (int i = len; i > 1; i--) { swap(a[i], a[1]); heapAdjust(a, 1, i - 1); } }