问题描述:
当数组中有很多重复的元素(Dupicate Keys)时,采用3-way partitioning,即把array分成三部分,一部分是小于duplicate keys的,一部分是等于duplicate keys,还有一部分是大于duplicate keys。当然,一轮partition只能让一种duplicate keys归位,如果其他数字也有duplicate的情况,则需要进行下一轮partition。
Goal:
算法思路:
- a[lo]作为pivot
- 从左向右扫描i(其实一直都是a[i]和pivot在比较)
- (a[i] < pivot): 交换a[lt]和a[i]; lt, i同时加1。
- (a[i] > pivot): 交换a[gt]和a[i]; gt减1。(i不变,因为交换后的i指向的元素还没有和a[lt]比较)
- (a[i] == pivot): i加1。
demo:
1. 初始化。
2. i+1,这一轮partitioning element是P;lt->P, i->A
3. A<<P, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->B (lt一直指向partitioning element)
4. B<<P, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->X
5. X>>P, 故a[gt]和a[i]交换,且gt-1;i->Z, gt->Y(gt已经减1了)
6. ZP, 故a[gt]和a[i]交换,且gt-1;i->Y, gt->C
7. Y>>P, 故a[gt]和a[i]交换,且gt-1;i->C, gt->P
8. CP, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->W
9. W>>P, 故a[gt]和a[i]交换,且gt-1;i->P, gt->D
10. P=P, 故i++; lt->P, i->P
11. P=P, 故i++; lt->P, i->P
12. P=P, 故i++; lt->, i->V
13. VP, 故 a[gt]和a[i]交换,且gt-1;i->D, gt->P
14. D<<P, 故a[lt]和a[i]交换,且lt, i同时+1;lt->P, i->P [此时pointers cross说明所有数都被scan过了]
Language: Java
private static void sort(Comparable[] a, int lo, int hi)
{
if (hi <= lo) return;
int lt = lo, gt = hi;
Comparable v = a[lo];
int i = lo;
while(i <= gt)
{
int cmp = a[i].compareTo(v);
if(cmp < 0)
swap(a[lt++], a[i++]);
else if(cmp > 0)
swap(a[i], a[gt--]);
else i++;
}
sort(a, lo, lt - 1);
sort(a, gt + 1, hi);
}
图片来源:Coursera
参考资料:Algorothm 4th
Happy Coding!