快速三向切分。按照书中所述,将重复的元素v放置于子数组两端,中间元素分为两个部分,左半部分小于v,右半部分大于v。才排序前需要遍历数组知道找到一个与首元素相等的元素,并将其放置到末尾。
如上图,当i与j相遇(i = j)时,过程“排序中”结束。
置换元素时,采用“头尾相遇”的方式,例如从lo和i开始相向置换元素直到一方到达边界p。
关键代码如下
public void sort (Comparable[] a) {
StdRandom.shuffle(a);
for(int i = 1; i < a.length; i ++) { //头元素和尾元素相等
if(a[i] == a[0]) {
exch(a, a.length - 1, i);
break;
}
} //end for
sort(a, 0, a.length - 1);
}
private void sort(Comparable[] a, int lo, int hi) {
if(hi <= lo) return;
int p = lo, q = hi;
int i = lo + 1, j = hi - 1;
Comparable v = a[lo];
while(i < j) {
if(a[i].compareTo(v) == 0) exch(a, i ++, p ++);
else if(a[i].compareTo(v) > 0) {
if(a[j].compareTo(v) == 0) exch(a, j --, q --);
else if(a[j].compareTo(v) < 0) exch(a, j --, i ++);
else j --;
} else i ++;
} //当i = j时循环结束
int m = lo, n = hi;
if(a[i].compareTo(v) > 0) i --;
if(a[j].compareTo(v) < 0) j ++;
while(m < p && i > p)
exch(a, m ++, i --);
while(n > q && j < q)
exch(a, n --, j ++);
sort(a, lo, j -1);
sort(a, i+1, hi);
}