快速排序(分治算法)

快速排序 (分治算法)

基本概念

快速排序可能是应用最广泛的排序算法,适用于各种不同的输入数据且在一般应用中比其他排序都要快的多。

快速排序是一种分治的排序算法。它将一组数组分成两个子数组,将两部分独立地排序,当两个子数组都有序是整个数组也就自然有序了。

  • 原地排序,只需要一个很小的辅助栈。
  • 将长度为 N N N 的数组排序所需时间和 N l g N NlgN NlgN 成正比

步骤

快速排序的基本思想是

  • 先从数列中取出一个数作为基准数
  • 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边
  • 再对左右区间重复第二步,直到各区间只有一个数

算法

java普通版

    public class Quick{
        public void sort(int arr[],int low,int high) {
           int l=low;
           int h=high;
           int povit=arr[low];

           while(l<h) {
                while(l<h&&arr[h]>=povit)
                   h--;
               if(l<h){
                   arr[l]=arr[h];
                   l++;
               }

               while(l<h&&arr[l]<=povit)
                   l++;
               if(l<h){
                   arr[h]=arr[l];
                   h--;
               }
           }
            arr[l]=povit;
           print(arr);
           System.out.print("l="+(l+1)+"h="+(h+1)+"povit="+povit+"\n");
           if(l-1>low)sort(arr,low,l-1);
           if(h+1<high)sort(arr,h+1,high);
       }
    }

减少交换次数,提高效率版

private <TextendsComparable<?superT>> voidquickSort(T[]targetArr,intstart,intend){
    int i=start,j=end;
    Tkey=targetArr[start];

    while(i<j){
        /*按j--方向遍历目标数组,直到比key小的值为止*/
        while(j>i&&targetArr[j].compareTo(key)>=0){
            j--;
        }
        if(i<j){
            /*targetArr[i]已经保存在key中,可将后面的数填入*/
            targetArr[i]=targetArr[j];
            i++;
        }
        /*按i++方向遍历目标数组,直到比key大的值为止*/
        while(i<j&&targetArr[i].compareTo(key)<=0){
        /*此处一定要小于等于零,假设数组之内有一亿个1,0交替出现的话,而key的值又恰巧是1的话,那么这个小于等于的作用就会使下面的if语句少执行一亿次。*/
            i++;
        }
        if(i<j){
            /*targetArr[j]已保存在targetArr[i]中,可将前面的值填入*/
            targetArr[j]=targetArr[i];
            j--;
        }
    }
    /*此时i==j*/
    targetArr[i]=key;//应加判断

    /*递归调用,把key前面的完成排序*/
    this.quickSort(targetArr,start,i-1);

    /*递归调用,把key后面的完成排序*/
    this.quickSort(targetArr,j+1,end);
    //两个递归应加判断
}

例子

举个例子 x[6] = { 64,57,86,42,12,53 } 六个数排序

012345
645786421253

第一步,开始地址 i = 0 ,结束地址 j = 5 ,基准值 key = 64

key012345
64645786421253

第二步,从后往前找比 key 小的第一个数 x[5] = 53 , i = 0 , j = 5 ,进行交换

key012345
64535786421264

第三步,从前往后找比 key 大的第一个数 x[2] = 86 , i = 2 , j = 5 ,进行交换

key012345
64535764421286

开始重复前面两步

第四步,从 j = 5 开始由后往前找比 key 小的第一个数 x[4] = 12 , i = 2 , j = 5 ,进行交换

key012345
64535712426486

第五步,从 i = 2开始由前往后找比 key 大的第一个数 x[5] = 86 , i = 5 ,j = 5 ,由于 i >= j 使用第一轮结束

64 左边的数都比它小,右边的数都比它大

然后在分别对 [0,3] 和 [5,5] 进行上述操作即可

i = 0 , j = 3key = 53

key012345
53535712426486

从后往前 x[3] = 42 , i = 0 , j = 3

key012345
53425712536486

从前往后 x[1] = 57 , i = 1 , j = 2

key012345
53425312576486

从后往前 x[2] = 12 , i = 1 , j = 2

key012345
53421253576486

[0, 3] 交换完成 [5, 5] 只有一个数,不用交换,自然有序

然后在对 [0, 1] 和 [3,3] 进行操作

i = 0 , j = 1key = 42

key012345
42421253576486

从后往前 x[1] = 12 , i = 0 , j = 1

key012345
42124253576486

[0, 1] 交换完成,整个数组排序完成

012345
124253576486

总结

快速排序的最差时间复杂度和冒泡排序是一样的都是O(N2),它的平均时间复杂度为O(NlogN)。

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值