基础版快速排序代码如下:
/*
* 基本排序算法
* */
public class QuickSort {
private QuickSort(){}
/*
* 对arr[l, r]部分进行partition操作
* 返回值p,使得arr[l, p-1] < arr[p], arr[p+1, r] > arr[p]
* */
private static int partition(Comparable[] arr, int l, int r){
Comparable v = arr[l];
int j = l; //arr[l+1, j] < v ; arr[j+1, i) > v
for(int i= l+1; i <= r; i++){
if(arr[i].compareTo(v) < 0){
swap(arr, ++j, i);
}
}
swap(arr, l, j);
return j;
}
//递归使用快速排序,对arr[l, r]的范围进行排序
private static void sort(Comparable[] arr, int l, int r){
if(l >= r)
return ;
int p = partition(arr, l, r);
sort(arr, l, p-1);
sort(arr, p+1, r);
}
public static void sort(Comparable[] arr){
int n = arr.length;
sort(arr, 0, n-1);
}
private static void swap(Object[] arr, int i, int j){
Object t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
public static Integer[] randomArray(int n, int min, int max) {
Integer[] arr = new Integer[n];
for(int i=0; i<n; i++)
arr[i] = new Integer((int)(Math.random() * (max - min + 1) + min));
return arr;
}
public static void main(String[] args) {
int N = 1000000;
Integer[] a = randomArray(N, 0, 2000);
long startTime = System.currentTimeMillis();
sort(a);
long endTime = System.currentTimeMillis();
//SortHelper.printArray(a);
System.out.println("排序所用时间为:" + (endTime - startTime) + "ms");
}
}
快速排序在处理一个巨大的无序数组时速度是非常快的,但是当其处理一个近乎有序的大数组时,其速度会大打折扣,在最差的情况下,他的算法复杂度甚至会退化到O(n^2)。导致其性能极速下降的原因如下:
在上面的代码中,我们每次取数组的第一个元素作为判断的基准点,在一个随机数组中没什么大问题,利用该基准点,我们每次可以将数组大致平均分为两个元素差不多的数组,然后再调用递归函数进行下一步的排序,其算法复杂度为O(nlogn).
然而处理一个近乎有序的数组时,我们每次取数组第一个元素作为基准点的话,该元素可能比后面的绝大部分元素小(或大),这样导致其算法复杂度会严重退化,性能大打折扣。在归并排序中,我们每次可以将数组平分为两个元素几乎相等的数组,所以在任何情况下,其算法复杂度可以保证为O(nlogn),执行效率不会有太大的变化。
该算法的小优化如下:
在一个近乎有序的数组中,我们可以随机选择一个元素作为基准点,这样就可以大大降低其算法复杂度退化的可能性(选择出一个元素比其他n-1个元素小(或大)的可能性为1/n,再选出一个元素比其他元素小(或大)的可能性为1/(n-1),以此类推,该算法复杂度退化为O(n^2)的可能性很小了)。而我们只需要改进partition()算法就可以了,代码如下:
private static int partition(Comparable[] arr, int l, int r){
int k = (int)(Math.random()*(r-l+1)) + l;
swap(arr, k, l);
Comparable v = arr[l];
int j = l; //arr[l+1, j] < v ; arr[j+1, i) > v
for(int i= l+1; i <= r; i++){
if(arr[i].compareTo(v) < 0){
swap(arr, ++j, i);
}
}
swap(arr, l, j);
return j;
}