Algorithm
- 打乱数组;
- 随机挑选一个值(一般取第一个),使得它的左侧全部小于他,右侧全部大于他;(用两个指针,一个遍历找到小于它的,一个遍历找到大于它的, 如果发现未知反了,那么交换两个指针当前位置的值)
- 将左右部分递归,得出有序数组
Implementation:
4. 找到索引位置
private int partition(Comparable[] a, int lo, int hi) {
int i = lo;
int j = hi;
while (true) {
// 找到需要与j交换的index i的位置
while (less(a[++i], a[lo])) {
// 如果越界了,那么就break
if (i == hi) {
break;
}
}
while (less(a[lo], a[j--])) {
if (j == lo) {
break;
}
}
// index已经全部遍历,那么说明已经有序,直接终止循环
if (i >= j) break;
// 关于这里为什么要取j的位置,因为当j遍历的数大于lo时,j还会移动,j会一直移动到小于lo的数值的位置
exch(a, lo, j);
// 返回的是位置
return j;
}
}
- 排序
private void quickSort(Comparable[]a) {
SdtRandom.shuffle(a);
sort(a, 0, a.length - 1);
}
private void sort(Comparable[] a, int lo, int hi) {
if (lo >= hi) return;
int index = partition(a, lo, hi);
sort(a, lo, index-1);
sort(a, index+1, hi);
}
几个要点:
1 指针停止位置比较复杂,需要多次练习;
2 如果存在相等的值,索引位置最好停在和其相同的值;
3.如果数组已经有序,或者有很多相同的值,那么效率是非常低的;
4.比mergesort效率高39%,但是通常实行时候比mergesort要快,因为数据移动比较少;
5.不稳定
** 改进
如果partition之后长度小于等于10了,可以改为用InsertionSort;
或者去中位数作为pivot;
Selection
(Leetcode 215, Leetcode 378, Leetcode 692)
private static Comparable select(Comparable[] a, int k) {
StdRandom.shuffle(a);
int lo = 0;
int hi = a.length - 1;
while (hi > lo) {
// 找到pivot
int j = partition(a, lo, hi);
if (j < k) lo = j + 1;
if (j > k) hi = j - 1;
if (j == k) return a[k];
}
return a[k];
}
** 这样的话就不需要排序,只要通过partition来找出在k位置的pivot就可以
Duplicate keys
Partition: 把等于pivot的值全部连在一起,也就是把array分成了三个区间
private void sort(Comparable[] a, int lo, int hi) {
if (hi <= lo) return;
int lt = lo;
int gt = hi;
// pivot(partitioning item)
Comparable v = a[lo];
int i = lo;
while (i <= gt) {
// 移动i, 和v比较,如果小,交换位置
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);
}
注:
Q:Why does \verb#Arrays.sort()#Arrays.sort() in Java use mergesort instead of quicksort when sorting reference types ?
The Java API for Arrays.sort() for reference types requires that it is stable and guarantees n \log nnlogn performance. Neither of these are properties of standard quicksort.
Quicksort uses less memory and is faster in practice on typical inputs (and is typically used by \verb#Arrays.sort()#Arrays.sort() when sorting primitive types, where stability is not relevant).