基本思想
快速排序也是基于分治算法的。步骤如下:
(1)选择一个基准元素,通常选择第一个元素或者最后一个元素;
(2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基 准元素值小。另一部分记录的元素值比基准值大;
(3)此时基准元素在其排好序后的正确位置;
(4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序
如下图所示:
Java版本实现
package sort;
public class QuickSort<T extends Comparable<? super T> > {
private T a[];
public QuickSort(T a[]) {
this.a = a;
}
public void quickSort() {
quickSort(0 , a.length - 1);
}
private void quickSort(int low , int high) {
if(low >= high) {
return;
}else {
T pivot = a[low];
int partition = partition(low , high ,pivot);
quickSort(low , partition - 1);
quickSort(partition + 1 , high);
}
}
private int partition(int low, int high , T pivot) {
while(low < high) {
while(low < high && pivot.compareTo(a[high]) <= 0) {
high --;
}
swap(low , high);
while(low < high && pivot.compareTo(a[low]) >= 0) {
low ++;
}
swap(low , high);
System.out.print(" ");
display();
}
return low;
}
private void swap(int low, int high) {
T temp = a[low];
a[low] = a[high];
a[high] = temp;
}
public void display() {
for(int i = 0 ; i < a.length; i ++ )
System.out.print(a[i] + " ");
System.out.println();
}
public static void main(String[] args) {
Integer a[] = {57,68,59,52,72,28,96,33,24,19};
QuickSort<Integer> qs = new QuickSort<>(a);
System.out.print("before sort:");
qs.display();
qs.quickSort();
System.out.print("after sort:");
qs.display();
}
}
算法分析
在归并排序中,我们详细推算了时间复杂度,快速排序与归并排序一样采取了分治算法,它的时间复杂度也是O(N*log2N)。
对于分治算法一般都是如此,用递归的方法把数据项分为两组,然后调用自身来分别处理每一组数据。算法实际上是以2为底,运行时间与N*log2N成正比。
对于快速排序来说,最理想的状态是随机分布的数据,即我们任意选定的枢纽处于中间位置,有一半元素小于它,有一半元素大于它。当数据时由小到大排列或者由大到小排列时,快速排序的效率最低,时间复杂度扩大为O(N2)。
算法改进
选定第一个元素为枢纽实现起来确实很简单,但是当它为最大值或最小值时,快速排序的效率会严重降低。假如选中的元素为数组的中值,自然是最好的选择,但是却要遍历整个数组来确定中值,这个过程可能比排序花费的时间还长,得不偿失。折衷的方法是找到数组中的第一个、最后一个以及处于中间位置的元素,选出三者的中值作为枢纽,既避免了枢纽是最值的情况,也不会像在全部元素中寻找中值那样费时间。这种方法被称为“三项取中法”(median-of-three)。
Java版本实现
public void quickSort2() {
quickSort2(0 , a.length - 1);
}
private void quickSort2(int low , int high) {
if(low >= high) {
return;
}else {
T pivot = pivot(low ,high);
int partition = partition(low , high , pivot);
quickSort2(low , partition - 1);
quickSort2(partition + 1 , high);
}
}
private T pivot(int left , int right) {
int mid = ( left + right ) / 2;
if(a[mid].compareTo(a[right]) > 0)
swap(mid , right);
if(a[left].compareTo(a[right]) > 0)
swap(left , right);
if(a[mid].compareTo(a[left]) > 0)
swap(mid, left);
return a[left];
}
private void swap(int low, int high) {
T temp = a[low];
a[low] = a[high];
a[high] = temp;
}