Skip to main content

Sorting

Sorting Algorithms

Summary

  • 强制稳定: 增加(唯一)时间戳, 修改 CompareTo 接口定义 => 当主元素相同时, 时间戳小的元素更小

Selection Sort

  • swap: O(n)
  • compare: O(n^2)

Insertion Sort

  • swap: O(n^2/4)
  • compare: O(n^2/4)

Shell Sort

  • swap: O(n^2/4)
  • compare: O(n^2/4)

Merge Sort

  • 利用 Merge Sort 计算逆序对个数: left[i] > right[j] => inversions += (mid - i + 1), 即所有 i~mid 元素都与 j 元素为逆序对
    // merge and count
private static long merge(int[] a, int[] aux, int lo, int mid, int hi) {
long inversions = 0;

// copy to aux[]
for (int k = lo; k <= hi; k++) {
aux[k] = a[k];
}

// merge back to a[]
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (aux[j] < aux[i]) { a[k] = aux[j++]; inversions += (mid -
i + 1); }
else a[k] = aux[i++];
}
return inversions;
}

// return the number of inversions in the subArray b[lo..hi]
// side effect b[lo..hi] is rearranged in ascending order
private static long count(int[] a, int[] b, int[] aux, int lo, int hi) {
long inversions = 0;
if (hi <= lo) return 0;
int mid = lo + (hi - lo) / 2;
inversions += count(a, b, aux, lo, mid);
inversions += count(a, b, aux, mid+1, hi);
inversions += merge(b, aux, lo, mid, hi);
assert inversions == brute(a, lo, hi);
return inversions;
}

/**
* Returns the number of inversions in the integer array.
* The argument array is not modified.
* @param a the array
* @return the number of inversions in the array. An inversion is a pair of
* indices {@code i} and {@code j} such that {@code i < j}
* and {@code a[i]} > {@code a[j]}.
*/
public static long count(int[] a) {
int[] b = new int[a.length];
int[] aux = new int[a.length];
for (int i = 0; i < a.length; i++)
b[i] = a[i];
long inversions = count(a, b, aux, 0, a.length - 1);
return inversions;
}
    // return Kendall tau distance between two permutations
public static long distance(int[] a, int[] b) {
if (a.length != b.length) {
throw new IllegalArgumentException("Array dimensions disagree");
}
int n = a.length;

int[] ainV = new int[n];
for (int i = 0; i < n; i++)
ainV[a[i]] = i;

Integer[] bNew = new Integer[n];
for (int i = 0; i < n; i++)
bNew[i] = ainV[b[i]];

return Inversions.count(bNew);
}

Quick Sort

  • partition: 哨兵(最后再将其归位) + 大循环 + 2 小循环, 交换元素法
  • partition: 辅助数组 brr, 3 循环(3 次扫描 arr) 分别将小/等/大于 guard 的数加入 brr
  • partition: 哨兵(最后再将其归位) + lo + hi, 外加 2 个动指针 leftLimit 与 rightLimit, 表示小于区的上界和大于区的上界
// lt eq gt three parts
void quick3waySort(int *a, int lo, int hi) {
if (hi <= lo) return;
int lt = lo, i = lo+1, gt = hi;
int v = a[lo];

while (i <= gt) {
int cmp = a[i].compareTo(v);
if (cmp < 0) exch(a, lt++, i++);
else if (cmp > 0) exch(a, i, gt--);
else i++;
}

sort(a, lo, lt - 1);
sort(a, gt + 1, hi);
}

Heap Sort

  • Built on Priority Queue
  • swap: 2NlgN + 2N (2NlgN for sink N times, 2N for construct MaxHeap)
  • compare: NlgN + N (NlgN for sink N times, N for construct MaxHeap)
// MaxPQ
void swim(int k) {
while (k > 1 && less(k/2, k)) {
exch(k/2, k);
k = k/2;
}
}

void sink(int k) {
while (2*k <= N) {
int j = 2*k;
if (j < N && less(j, j+1)) j++;
if (!less(k, j)) break;
exch(k, j);
k = j;
}
}

Radix Sort

基数排序 (可用于混乱 shuffle 数组):

  • 从个位到高位放入桶
  • 从高位到个位放入桶

Sorting Algorithms Performance