接: http://blog.csdn.net/luotuomianyang/article/details/51785440
5.快速排序
基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快排中,切分的位置取决于数组的内容,其步骤如下:
- 先随意的取a[lo]作为切分元素,即那个将会被排定的元素;
- 从左端开始扫描直到找到第一个大于它的元素;
- 在从右端开始向左扫描,直到找到一个小于它的元素;
- 这两个元素很明显没有排定,则交换其位置;
- 如此继续,这样就可以保证左指针i的左侧元素都不大于切分元素,右指针j的右侧元素都不小于切分元素;
- 当两个指针相遇时,只需把切分元素a[lo]和左子数组的最右侧元素(a[j])交换然后返回j即可。
上代码:
public class Fast {
public static void main(String[]args){
int[]a = {0,1,2,3,4,5,6,9,6,8,5,2,4,3,1,0};
StdRandom.shuffle(a);//消除对输入的依赖,即把上述数组元素打乱
fastSort(a,0,a.length-1);
for(int i=0;i<a.length;i++){
System.out.print(a[i]+" ");
}
}
private static void fastSort(int[] a ,int lo,int hi){
if(hi<=lo) return;
int j = partition(a, lo, hi);
fastSort(a,lo,j-1);
fastSort(a,j+1,hi);
}
/**
* 将数组切分为a[lo..i-1],a[i],a[i+1..hi]
* @param a
* @param lo
* @param hi
* @return
*/
private static int partition(int[]a,int lo,int hi){
int i = lo;
int j = hi+1;
int v = a[lo];
while(true){
//此处为++i,从第一个开始扫描,
//因为交换的i和j在循环外,故若使用i++,则交换的值为真实值+1
//若交换与i++发生的循环再一起,则可以用i++
while(a[++i] < v)
if(i==hi) break;
while(v < a[--j])//此处为--j
if(j==lo) break;
if(i>=j) break;
//exch(a,i,j)
int tmp = a[i];
a[i]=a[j];
a[j]=tmp;
}
a[lo]=a[j];
a[j]=v;
return j;
}
}
其中把数组乱序的代码如下:
/**
* 随机打乱指定的int型数组
* @param a 待打乱的int型数组
*/
public static void shuffle(int[] a) {
int N = a.length;
for (int i = 0; i < N; i++) {
int r = i + uniform(N-i);
int temp = a[i];
a[i] = a[r];
a[r] = temp;
}
}
最后结果
0 0 1 1 2 2 3 3 4 4 5 5 6 6 8 9
快速排序切分方法的内循环会用一个递增的索引将数组元素和一个定值比较,这种简洁性是它的一个优点,归并和希尔排序比快速排序慢的原因就是它们需要在内循环中移动数据;快速排序的另一个优势在于它的比较次数小,排序的最终效果最终还是依赖于切分数组的效果。
缺点:切分可能发生在任何位置,切分超级不平衡时程序效率会极低。
<未完待续.....>