【每天学一点 - 算法篇 - 排序 - 快速排序】

系列文章目录

【每天学一点 - 算法篇 - 排序 - 插入排序】
【每天学一点 - 算法篇 - 排序 - 希尔排序】
【每天学一点 - 算法篇 - 排序 - 堆排序】
【每天学一点 - 算法篇 - 排序 - 归并排序】



前言

新的一年,祝大家吉时吉日吉如风,丰年丰月如风增,增福增禄增长寿,寿山寿水寿长生,生财生利生贵子,子孝孙贤代代荣,荣华富贵年年有,有财有势有前程。


一、什么是快速排序

快速排序不像前面说的插入排序,缩减增量排序,堆排序,归并排序那样,排序方式就是排序名字,很好理解,快速排序在只用到比较的排序算法中就已经是非常小的时间复杂度,又保持住了空间复杂度没有扩展,所以只能说这种排序确实很快速,嗯,就是这样,快速排序


二、快速排序原理

1、思路

快速排序也是用的分治的思路,提到分治,自然最先想到归并排序,
因为都是分治,所以快速排序还是可以跟归并排序放在一起理解的。
归并是通过将数组分到最小,然后合并的时候进行排序,
而快速排序则是在将数组往小分的时候保证一定程度有序,分到最后形成有序数组。
之前说过,归并排序快是快在通过临时数组储存了每次比较得到的比较关系,
而快速排序则是在当前数组里面,去切分出左右两个数组,
这样就即储存了比较关系,又保持了空间复杂度没有变高。

快速排序还有一个比较重要的点就是如何去选取一个合适的数,
来跟每个数子比较,能让切分出来的左右两个数组尽可能大小相近,
这个数本可以是数组中任意的随机一个数,
为防止数组可能预排序过或为倒序数组,故可选取数组最中间的数作为基础值

2、示例

在这里插入图片描述

3、抽象

选取数组中间位置数字为基础值,
从数组左侧向右依次寻找小于基础值数字,
找到后再从数组右侧向左依次寻找大于基础值数字,
均寻找到后,两个数字进行交换,
持续进行左右数字的查找和交换,
直到左边数组为小于基础值数组,右边数组为大于基础值数组,
然后左边数组和有右边数组再分别进行快速排序,
数组无法再分,则完成整体排序

4、改进

1)基础值的选取可改进为通过选最左的数,中间的数,最右的数进行预排序,
小值放入数组首位,大值放入数组末尾,由中值作为基础值,可提升基础值的可靠性。
2)因为被选中的基础值预计就是要保存在左右两组之间,并不需要参与左右两组之间位置的交换,
所以实际使用中,一般先将基础值存放在数组末端,等完成左右分组后再放回两组的中间位置。
3)改进方向均为考虑较大数组排序情况,所以分治过程中,数组小于一定程度时,可改为较简单的插入排序快速完成排序。


三、快速排序代码

实现方法

    private void quickSort(int[] a, int left, int right) {
        //数组较大时用快速排序,否则用插入排序
        if (right - left > CUTOFF) {
            //由数组最左,最右,和中间三个数预排序,选取基础值并放在右边第二个
            int base = mid(a, left, right);
            int i = left, j = right - 1;
            for (; ; ) {
                //数组从左往右查找大于基础值的数
                while (a[++i] < base) {
                }
                ;
                //数组从右往左查找小于基础值的数
                while (a[--j] > base) {
                }
                ;
                if (i < j) {
                    swap(a, i, j);
                } else {
                    break;
                }
            }
            //此时以i为分界,分为左右两组
            swap(a, i, right - 1);
            //左右两组再分别进行快速排序
            quickSort(a, left, i - 1);
            quickSort(a, i + 1, right);
        } else {
            insertionSort(a, left, right);
        }
    }

预排序方法


    private int mid(int[] a, int left, int right) {
        int mid = (left + right) / 2;
        if (a[left] > a[mid]) {
            swap(a, left, mid);
        }
        if (a[left] > a[right]) {
            swap(a, left, right);
        }
        if (a[mid] > a[right]) {
            swap(a, mid, right);
        }
        swap(a, mid, right - 1);
        return a[right - 1];
    }



四、快速排序复杂度

老规矩,先写结论

O(NlogN)

原因上面也大概说了,时间复杂度就类比归并排序看就可以,开始排序的好处在于除了时间复杂度比较优秀,而且没有造成空间复杂度的变化


总结

继续闭关修炼。。。。。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

破晓星芒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值