对快排模板简单的理解和几个注意点的原理

对快排模板简单的理解和几个注意点的原理

源码:

\qquad 先直接贴代码,对快排本身有一定理解的同学可以直接看注意点的注释

class Solution {
public:
    void quicksort(vector<int>& nums,int l,int r){
        if(l>=r)return;
        int pivot=nums[l+(r-l)/2],i=l-1,j=r+1;
        while(i<j){
            while(nums[++i]<pivot);
            while(nums[--j]>pivot);//后++后--会让交换时的ij变化,使交换错误兄弟
            if(i<j)swap(nums[i],nums[j]);
        }
        quicksort(nums,l,j);//选j因为取中值时l+(r-l)/2偏左且不会取到r AMD,yes!
        quicksort(nums,j+1,r);//j+1因为j=i-1或j==i
    }
    vector<int> sortArray(vector<int>& nums) {
        quicksort(nums,0,nums.size()-1);
        return nums;
    }
};

基本思路

\qquad 分治法,每次递归要保证完成分治点左边均小于等于pivot,右边均大于等于pivot
举例:
初始1
初始,这图漏了数组元素:5,1,1,2,0,0,pivot=1;

第一个循环1
\qquad 第一次进大while循环两个小while之后i,j停下的位置,这图漏了标交换,这次是交换0和5(T▽T),没事下个图就标有了
请添加图片描述
\qquad 第二次进while循环两个小while之后i,j停下的位置
请添加图片描述
\qquad 第三次就i,j相遇了,此时j的左边都小于等于pivot,右边都大于等于pivot,至此这次函数的基本使命就完成了,接下来就是左右分配任务递归了
(函数:我滴任务,完成力!------开始传承接下来每个函数都干同样的事,直到传进的l>=r 便结束递归不再传承)
请添加图片描述

模板中几个注意点

1. pivot的取值

\qquad 一般来说初学接触到的多是pivot=nums[l],也就是取最左边。不过我个人喜欢直接取中值偏左,中值可以较大概率的对题目中数据尽可能进行均匀分区(分区:上图绿色部分的分区,也是接下来递归函数需要执行的区域) 当然还是有其他取值方式,比如靠运气决定运行速度的随机化取值

srand((unsigned)time(NULL));
int random_number=rand()%(right-left+1)+left;
int pivot=nums[random_number]

再比如三值取中法:取首位值和中值和末尾值的平均值

//			首位值	     中值		末位值
int pivot=(nums[l]+nums[l+(r-l)/2]+nums[r])/3;

2. i和j的取值为什么是l-1和r+1

\qquad 我也曾想为什么不能直接 i=l,j=r; 然后后面的小while里用

            while(nums[i++]<pivot);
            while(nums[j--]>pivot);

但是后++后–的方式会使 i 和 j 在不满足小while的条件要退出后多执行一次++和–,这影响了后面交换使用的 i 和 j ,好点的会漏几个数没排,大概率是直接访问到数组外去了

什么?你问为什么小while一定要改成后++?不可以还是前++马?呃,可以,但你nums[l]和nums[r]还是要判断的吧,所以会需要类似特判的,在while之前先判断一次[ l ]和[ r ],如果你觉得好记的话,也可以

\qquad 所以不如从了我吧(bushi),咱们为了之后的幸福各退一步往两边取值(〃>_<;〃)

3. 小while里的[++i]和[–j]

\qquad 嗯,其实跟上面那个疑问的解答本质是一样的,都是为了完整遍历范围内的元素,不想前++的解决方案也一样,你可以先处理nums[ l ]和nums[ r ]看需不需要将指针停下,但是要注意和之后的小while里配合好,避免漏数

4. 递归为什么一定要 j,不可以 i 吗

\qquad 不可以,起码在这套模版一点不改的情况下不可以,会出现边界问题,因为我们在取pivot值时会影响到最后递归的取值。
\qquad 什么情况下会出现边界问题?

当pivot取nums[l]时(可以看成取i),递归还是取了[l,i-1]和[i,r]
当pivot取nums[r]时(可以看成取j),递归还是取了[l,j]和[j+1,r]
什么是边界问题:

请添加图片描述此时会无限递归[0,1]区间

所以呀(˘•ω•˘)

当pivot取得到nums[l]时递归只能从[l,j]和[j+1,r]
当pivot取得到nums[r]时递归只能从[l,i-1]和[i,r]










\


掺点私货
请添加图片描述
生命因何而沉睡?诸君,共勉!
就酱,再见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值