图解快速排序


前言

快速排序是应用相当广泛的排序算法,在Java的java.util.Arrays这个类里面的sort()方法就是使用的快速排序,其内部是调用了一个类的静态方法DualPivotQuicksort.sort(),此类实现了Vladimir Yaroslavskiy,Jon Bentley和Josh Bloch的Dual-Pivot Quicksort算法。 该算法可在许多数据集上提供O(n log(n))性能,这会导致其他快速排序降级为二次性能,并且通常比传统的(单轴)Quicksort实现要快。 所有公开的方法都是程序包专用的,旨在在执行任何必要的数组边界检查并将参数扩展为所需形式之后从公共方法(在Arrays类中)调用.在面试中,也经常要求面试者能手撕快速排序。接下来我们就对快排来一探究竟。

快速排序是什么?

  • 快速排序算法是一种分治的排序算法,是对冒泡排序的一种改进算法,快速排序的实现核心思想就是对原始数组进行分而治之,递归调用,从而实现对数组的排序,并且时间复杂度与NlogN 成正比。

图解快速排序

  • 以数组[7,11,4,3,8,10,2,13,5,14]为例子,一步一步的图解刨析快速排序。
  • 快速排序的第一步是找到一个基准数,将数组以这个基准数,分为两部分,右边的是小于基准数的,左边的是大于基准数的。为了方便处理,我们都是以数组第一个元素作为基准数的。 此时基准数为temp=7.
    在这里插入图片描述

第一轮,

① right向左移动,执行right–运算,直到arr[right]小于基准数temp=6时,就暂停移动;left向右移动,执行left++运算,直到arr[left]>temp时,停止移动,然后交换arr[right]和arr[left]的值。
在这里插入图片描述

  • ② 重复第一步 操作。

在这里插入图片描述

  • ③ 比较关键的一步来了,此时right继续左走,走到arr[right]=2时,发现是小于基准数6,这时候停止移动。最最关键的来了,那么此时left还需要继续走吗? 答案 是否的。 因为此时left已经和right相遇了,这是终止每一轮的条件,即left<right.
    在这里插入图片描述
  • ④ 我们经过第一轮的左右指针移动,比较并交换左右指针的值,这一系列的最终目的就是使得我们的数组 被分割为两部分:基准数左边的数小于 它,而右边的数要大于它。 那么紧接着就 将arr[left]与基准数进行交换,就达到了我们的目的。
  • 在这里插入图片描述
  • 如此一来,经过第一轮的遍历交换,我们就将 数组 基准数的右边 都小于了它, 左边都大于它。

第二轮

接下来干嘛??我们经过第一轮的操作,达成了我们的初步目标,要实现全面排序,后面还得继续重复第一轮的操作,直到整个数组完全有序为至。如何重复呢? 我们先从第一轮基准数的右边开始,分割出数组[2,5,4,3],重复第一轮的操作。此时的基准数temp=2.

在这里插入图片描述

  • ① right 向左移动,直到 遇到 小于等于基准数的值时停止左边移动。left准备右移动时,已经left==right了 已经满足 基准数的左边 大于右边的要求了,那么就自我交换一次。并从基准数的右边开启第三轮的操作。
    在这里插入图片描述

第三轮

  • 依旧重复 第一轮的操作。
    在这里插入图片描述
  • ① 初始时right所在的元素已经小于的基准数temp=5了,那么直接不移动,然后left开始右移动,沿途没有发现大于基准的元素,因此直到left==right时,停止移动。 并将arr[left]与基准数temp进行交换。在这里插入图片描述
    此时 已 temp=7为基准数的数组的右边已经完全有序了,那么继续对基准数左边的数组重复第一轮即可得到完整的排序数组。
    在这里插入图片描述

总结

  • 从整个流程可以发现,快速排序的比较和交换次数比冒泡排序少很多,并且也很少移动元素,这是快速排序比其他排序快的重要因素。但并不意味着,这是最优的快速排序算法。快速排序的应用实际上还要看具体场景,对于小数组的排序,当数组元素小于47时,优先选择插入排序进行排序。如果要排序的是字节数组的长度大于29,则优先使用计数排序而不是插入排序.如果要排序的short或char数组的长度大于3200,则优先使用计数排序而不是Quicksort.
  • 最后附上 代码 仅供参考
  void quieckSort(int [] arr,int start,int end){
        if(start>end)
             return;
        //以第一个元素作为基准数
        int temp=arr[start];
        int left=start;
        int right=end;
        while(left<right){
            //在右边找到小于基准数的值
            while(left<right&&arr[right]>=temp){
                right--;
            }
            //在左边找到大于基准数的值
            while(left<right&&arr[left]<=temp){
                left++;
            }
            //交换这两个值
            if(right>left){
                int t=arr[left];
                arr[left]=arr[right];
                arr[right]=t;
            }
        }
        //基准数的交换
        arr[start]=arr[left];
        arr[left]=temp;
        //递归 对 基准数 的左右两边继续快排
        quickSort(arr,start,left-1);
        quickSort(arr,left+1,end);
    }
  • 如果对你有帮助 就点一个赞吧。嘻嘻。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值