publicclassSelection{ publicstaticvoidsort(Comparable[] a){ // 将a[]按升序排列 int N = a.length; // 数组长度 for (int i = 0; i < N; i++) { // 将a[i]和a[i+1..N]中最小的元素交换 int min = i; // 最小元素的索引 for (int j = i + 1; j < N; j++) if (less(a[j], a[min])) min = j; exch(a, i, min); } } // less()、exch()、isSorted()和main()方法见“排序算法类模板” }
privatestaticvoidsort(Comparable[] a, int lo, int hi){ if (hi <= lo) return; int j = partition(a, lo, hi); // 切分(请见“快速排序的切分”) sort(a, lo, j - 1); // 将左半部分a[lo .. j-1]排序 sort(a, j + 1, hi); // 将右半部分a[j+1 .. hi]排序 } }
1 2 3 4 5 6 7 8 9 10 11 12 13
privatestaticintpartition(Comparable[] a, int lo, int hi){ // 将数组切分为a[lo..i-1], a[i], a[i+1..hi] int i = lo, j = hi + 1; // 左右扫描指针 Comparable v = a[lo]; // 切分元素 while (true) { // 扫描左右,检查扫描是否结束并交换元素 while (less(a[++i], v)) if (i == hi) break; while (less(v, a[--j])) if (j == lo) break; if (i >= j) break; exch(a, i, j); } exch(a, lo, j); // 将v = a[j]放入正确的位置 return j; // a[lo..j-1] <= a[j] <= a[j+1..hi] 达成 }
将长度为 N 的无重复数组排序,快速排序平均需要 ~2NlnN 次比较(以及 1/6 的交换)。
快速排序最多需要约$N^2 / 2 $次比较,但随机打乱数组能够预防这种情况。
不存在任何基于比较的排序算法能够保证在 NH-N 次比较之内将 N 个元素排序,其中H 为由主键值出现频率定义的香农信息量。
对于大小为 N 的数组,三向切分的快速排序需要 ~(2ln2)NH 次比较。其中 H 为由主键值出现频率定义的香农信息量。
在一个大小为 N 的索引优先队列中,插入元素(insert)、改变优先级(change)、删除(delete)和删除最小元素(remove the minimum)操作所需的比较次数和 logN 成正比。
用下沉操作由 N 个元素构造堆只需少于 2N 次比较以及少于 N 次交换。
堆排序
1 2 3 4 5 6 7 8 9
publicstaticvoidsort(Comparable[] a){ int N = a.length; for (int k = N / 2; k >= 1; k--) sink(a, k, N); while (N > 1) { exch(a, 1, N--); sink(a, 1, N); } }