分治思想-理解快速排序

原理

快速排序vs归并排序,前者基于数值大小划分,后者基于index划分。

快速排序不需要额外的存储空间,这一点使得它优于归并排序,因为归并排序需要额外一倍存储空间存储排序数组。

快速排序从数组中找一个pivot,将小于piovt的放到左边,大于pivot的放到右边。伪代码如下:

QuickSort(A):
    S− ={};S+ ={};//s-存小于,s+存大于
    Choose a pivot A[j];//随机选择
    
    for i=0 to n−1 do
        Put A[i] in S− if A[i] < A[j];
        Put A[i] in S+ if A[i] ≥ A[j];
    
    QuickSort(S+);
    QuickSort(S−);
    
    Output S−, then A[j], then S+;

时间复杂度

  • 估算时间复杂度

考虑两种极端情况

  1. 最好情况:pivot每次都选中了中位数

T ( n ) = 2 T ( n 2 ) + O ( n ) = O ( n l o g n ) T(n)=2T(\frac{n}{2})+O(n) = O(nlogn) T(n)=2T(2n)+O(n)=O(nlogn)

  1. 最坏情况:pivot每次都选中了最边上的数

T ( n ) = T ( n − 1 ) + O ( n ) = O ( n 2 ) T(n)=T(n-1)+O(n) = O(n^2) T(n)=T(n1)+O(n)=O(n2)

  1. 一般情况:大概率选中偏中间的数

T ( n ) = O ( n l o g n ) T(n) = O(nlogn) T(n)=O(nlogn)

假设取pivot的时候使得划分比例是3:1,由于每一次划分的额外开销是O(n)所以总的时间复杂度是O(nlog_\frac{4}{3}n)=O(nlogn),和最好情况一样的复杂度,同样的,按8:1,100:1的划分也都有O(nlog_\frac{9}{8}n)=O(nlog_\frac{101}{100}n)=O(nlogn)

pivot选择

由上分析可知,快速排序的好坏与pivot有关。为了使得pivot选的更接近中间,有以下几种思路提高划分效果:

  1. 随机采样选三个元素,取中位数作为pivot
  2. 取首中尾三个元素,取中位数作为pivot
  3. 直到选到合适的pivot再划分:添加一层循环,每一层划分之后判断一下∣S−∣≥n/4,∣S+∣≥n/4|,两个条件是否成立,如果不成立,则重新选择,否则退出循环

实现代码

public class QuickSort {
    
    
    //数组内的数换位
    private void swap(int[]A,int s,int r){
    
    
        if(s!=r){
    
    
            A[s] += A[r];
            A[r] = A[s] - A[r];
            A[s] = A[s] - A[r];
        }
    }

    //选pivot,写成接口方便修改
    private int findpivot(int[] A,int l,int r){
    
    
        return (l+r)/2;
    }

    //划分
    private int partition(int[] A,int l,int r,int p){
    
    
        do{
    
    
            while(A[l]<p) {
    
     l++; }
            while((l<r) && A[r]>=p) {
    
     r--; }
            swap(A,l,r);
        }while (l<r);
        return l;
    }

    private void quicksort(int[] A,int l,int r){
    
    
        if(l<r) {
    
    
            int p = findpivot(A, l, r);
            swap(A, p, r);
            int k = partition(A, l, r - 1, A[r]);
            swap(A, k, r);
            quicksort(A, l, k - 1);
            quicksort(A, k + 1, r);
        }
    }

    public static void main(String[] args) {
    
    
        int[] data = new int[]{
    
    4,5,7,6,2,3,1,8};
        QuickSort test = new QuickSort();
        test.quicksort(data,0,data.length-1);
        for(int i=0;i<data.length;i++){
    
    
            System.out.println(data[i]);
        }

    }
}

猜你喜欢

转载自blog.csdn.net/qq_32505207/article/details/106261705