双路快速排序是快排的优化版。
双路快排的思想是,在待排序数组 [l, r]
的头和尾分别设置一个指针 i = l + 1
和 j = r
,使得 arr[l+1...i) <= v;arr(j...r] >= v
。这样可以使算法在待排序数组的左右两边同时推进。
问题:
- 为什么是
arr[l+1...i) <= v
而不是 arr[l...i) <= v
?因为 l
被拿去用来做标定点 v
了。
- 为什么标定点两边都有等于
v
的元素?具体原因请看代码注释。
public class QuickSort2Ways { public void sort(Comparable[] arr) { int n = arr.length;
quickSort2Ways(arr, 0, n - 1); }
private void quickSort2Ways(Comparable[] arr, int l, int r) { if (r <= l) return;
int p = partition(arr, l, r);
quickSort2Ways(arr, l, p - 1); quickSort2Ways(arr, p + 1, r); }
private int partition(Comparable[] arr, int l, int r) { swap(arr, l, (int) (Math.random() * (r - l + 1)) + l);
Comparable v = arr[l];
int i = l + 1, j = r;
while (true) { while (i <= r && arr[i].compareTo(v) < 0) i++;
while (j >= l + 1 && arr[j].compareTo(v) > 0) j--;
if (i > j) break;
swap(arr, i, j);
i++; j--; }
swap(arr, l, j);
return j; }
private void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
|
public class QuickSort2Ways { public void sort(Comparable[] arr) { int n = arr.length;
quickSort2Ways(arr, 0, n - 1); }
private void quickSort2Ways(Comparable[] arr, int l, int r) { if (r <= l) return;
int p = partition(arr, l, r);
quickSort2Ways(arr, l, p - 1); quickSort2Ways(arr, p + 1, r); }
private int partition(Comparable[] arr, int l, int r) { swap(arr, l, (int) (Math.random() * (r - l + 1)) + l);
Comparable v = arr[l];
int i = l + 1, j = r;
while (true) { while (i <= r && arr[i].compareTo(v) < 0) i++; while (j >= l + 1 && arr[j].compareTo(v) > 0) j--;
if (i > j) break;
swap(arr, i, j);
i++; j--; }
swap(arr, l, j);
return j; }
private void swap(Object[] arr, int i, int j) { Object t = arr[i]; arr[i] = arr[j]; arr[j] = t; } }
|
另外,使用快速排序还可以解决「数组中的第 K 个最大元素」问题。
第 K
个最大元素,在升序排序的数组中对应的位置是 [len - K]
,假设数组长度为 len
。
partition
方法的返回值就是:partition
方法中的标定点 p
在当前排序好的数组中的位置。