此文主要参考Algorithms, 4th Edition,Robert Sedgewick and Kevin Wayne
快速排序算法是一个很重要的算法,提供了解决问题一个重要的思想。基本的过程如下:
- 将数组随机打乱
- 进行分组,找到一个j 使得
- a[j]排好序
- 其左边的数都不大于a[j]
- 其右边的数都不小于a[j]
- 分别对左边和右边进行排序
public class quickSort {
private static int partition(int[] a,int lo,int hi){
int i = lo,j = hi + 1;
while(true){
// 找到比a[lo] 大的数
while( a[++i] < a[lo])
if( i==hi )break;
// 找到比a[hi] 小的数
while( a[lo] <a[--j])
if( j== lo ) break;
if (i >= j) break;
//交换i,j 下标的值,
//那么就保证比a[lo] 小的被交换到左边,大的交换到右边
exch(a,i,j);
}
//最后结束时
//i一定指向比a[lo]大的数字或者最后一个数,
//j一定指向比a[lo]小的数字或者最头上的数,将小数与a[lo]交换
exch(a,lo,j);
return j;
}
private static void sort(int[] a, int lo,int hi){
if( hi <= lo) return;
int j = partition(a,lo,hi);
sort(a,lo,j-1);
sort(a,j+1,hi);
}
private static void exch(int[] a,int lo,int hi){
int tmp;
tmp = a[lo];
a[lo] = a[hi];
a[hi] = tmp;
}
}
while( a[++i] < a[lo])
if( i==hi )break;
假如我这里用的是 <= 号而不是 < 号快排算法在一些情况下就退化成O(N^2) 了,下面是一些解释。快速排序算法在1962年被提出来,在1990年的时候C语言的用户发现了系统提供的qsort(),当排序的数组中含有大量的相同的关键字时,算法退化成O(N^2)复杂度。错误的根源在于:把所有与轴的关键词相同的项都放到了轴的一边(轴,就是partion过程中作为基准的那一项,上面代码中的a[lo])。
比如有如下序列:
A A A A A A A A A A 那么第一次分割,返回的结果就是最后一位,规模变为n-1,然后第二次分割返回的分割点是倒数第二位,规模变成 n-2...
二、我们做了很多没必要的交换
我们仍然考虑全是A 的例子
while(true){
// 找到比a[lo] 大的数
while( a[++i] < a[lo])
if( i==hi )break;
// 找到比a[hi] 小的数
while( a[lo] <a[--j])
if( j== lo ) break;
if (i >= j) break;
//交换i,j 下标的值,
//那么就保证比a[lo] 小的被交换到左边,大的交换到右边
exch(a,i,j);
}
每一次循环,i增加1,j减少1,并且交换,这些交换的开支严重影响了算法的效率,这是没有必要的。
上面两种现象的原因都是因为没有很好的处理相同的关键字排序,后来Dijkstra 提出来3-way快排,很好的处理了这个问题。
将数组分成三部分:在lt 和 gt 之间的部分都是与 轴相同的项,左边的是小于的项,右边的是大于的项,如图
因此可以得到如下算法:
- v=a[lo]作为分割轴
- 从左向右扫描下标i
- (a[i] < v) 交换a[lt] 和 a[i]; 并且自增lt 和 i;
- (a[i] > v )交换a[gt] 和 a[i];并且自减gt;
- (a[i] == v) 自增i;
private static void sort(int[] a, int lo,int hi){
if(hi <= lo) return;
int lt = lo,gt = hi;
int v = a[lo];
int i = lo;
while(i <= gt){
if( a[i] < v) exch(a,i++,lt++);
else if( a[i] > v) exch(a,i,gt--);
else i++;
}
sort(a,lo,lt-1);
sort(a,gt+1,hi);
}
总的来说以前只知道快排在原数组排好序的情况下,性能会退化,不知道在很多key 值相同的情况下也会退化。
本文深入探讨了快速排序算法,包括其随机化步骤和分组策略。通过找到分割轴并确保数组元素正确分布,实现递归排序左右子数组。同时,文章提及了Dijkstra的3-way快速排序方法,进一步丰富了排序算法的理解。
946

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



