看了教科书上的快排,又对比了“Algorithm 4th”里的快排,感觉后者更加简洁清晰,而且成功cover极端情况,故决定采用“Algorithm 4th”里面的快排代码。
算法思路:
一轮 QuickSort Partition有两个phase:
phase 1:重复步骤直到i, j指针交叉
- 从左向右扫描i指针(只要满足
a[i]<a[lo],当然,一开始把a[lo]作为pivot了) - 从右向左扫描j指针(只要满足
a[j]>a[lo])
phase 2: 当i, j交叉时
- 交换
a[lo]和a[j](注意!不是交换a[i]!因为此时a[j]能保证是小于等于a[lo]的。)
以上一轮过程就是partition。
Language: Java
Partition过程:(一轮归位)
private static int partition(Comparable[] a, int lo, int hi)
{
int i = lo, j = hi+1;//之所以是hi+1是因为下面是--j,j要先减1然后再对比
while(true)
{
while(less(a[++i], a[lo]))
if(i == hi) break;
while(less(a[lo], a[--j]))
if(j == lo) break;
if(i >= j)break;检测i,j是否交叉
swap(a[i], a[j]);//如果i,j尚未相遇,则交换
}
swap(a[lo], a[j])//注意是和a[j]不是a[i]交换!
return j;//返回被正确归位的元素位置
}
QuickSort完整过程:
public class Quick
{
private static int partition(Comparable[] a, int lo, int hi)
{/*见上面代码*/}
public static void sort(Comparable[] a)
{
StdRandom.shuffle(a);//Shuffle是很重要的
sort(a,0,a.length-1);//正式开始排序
}
private static void sort(Comparable[] a, int lo, int hi)
{
if(hi <= lo) return;
int j = partition(a,lo,hi);//j是已归位位置
sort(a,lo,j-1);
sort(a,j+1,hi);
}
}
QuickSort 细节:
- QuickSort比MergeSort的优点在于快排的partition是in-place的,不会占用多余空间。
- 判断指针是否交叉是很关键的一个环节
- 越界判断:
i==hi是必须的,j==lo是redundant的。 - Shuffling is needed for performance guarantee.
- Equal Keys. 当有待排序数列中有重复元素时,在和pivot相同的元素位置上停下来会更好。(尽管counter-intuitive,见下一节笔记。)
- Best case: O(NlogN)O(NlogN),有点像二分法;Worst case: O(N2)O(N2)
不仅快排是面试常考算法,其中的Partition也是Leetcode常用代码。

本文详细介绍了快速排序算法的实现原理及具体代码实现。通过对比不同教材中的快排算法,选取了一种简洁且能有效处理极端情况的方法。文章还深入探讨了快速排序的分区过程,并提供了完整的Java实现。
465

被折叠的 条评论
为什么被折叠?



