• [题] 快速排序 #分治


    题目

    快速排序


    题解

    边界问题很麻烦
    参考博客


    代码

    #include 
    using namespace std;
    const int N = 100010;
    int q[N];
    void quick_sort(int l, int r){
    	//只有一个元素 或 不存在元素
        if (l >= r) return;
        //i在l前一位开始,j在r右一位开始 
        int i = l - 1, j = r + 1;
        //找到中间位的元素mid做一个大小判别标准 
        //如果用i做分界线的话要向上取整mid = q[l + r + 1 >> 1];
    	//如果用j做分界线的话要向下取整mid = q[l + r >> 1];
    	int mid = q[l + r >> 1];
    	//注意循环条件是i
        while (i < j) {
        	//直到i找到左边第一个不小于mid的元素 
            do {
    			i ++ ;
    		} while (q[i] < mid);
    		//直到j找到右边第一个不大于mid的元素 
            do {
    			j -- ; 
    		} while (q[j] > mid);
    		//如果两个元素同时存在就进行交换 
            if (i < j) 
    			swap(q[i], q[j]);
        }
        //对左右两边进行同样的二分操作 
    //    以下是用i为界限的写法 
    //    quick_sort(l, i + 1);
    //    quick_sort(i, r);
        quick_sort(l, j);
        quick_sort(j + 1, r);
    }
    int main(){
        int n;
        cin >> n;
        for(int i = 0; i < n; i ++) 
    		scanf("%d", &q[i]);
        quick_sort(0, n - 1);
        for(int i = 0; i < n; i ++) 
    		printf("%d ", q[i]);
        return 0;
    }
    /*
    问:为什么是[l,i-1][i,r]?
    答:因为i会先自加,最后位置会靠后
    问:为什么是[l,j][j+1,r]?
    答:因为j会先自减,最后位置会靠后 
    
    问:关于边界问题。 
    答: 
    因为这是一个二分的问题,所以边界问题至关重要
    我们担心n个数出现划分成0和n两部分无限划分的情况 
    对于取i还是j,和边界有关
    结论如下: 
    以j为划分时,x不能选q[r],向下取整 
    若以i为划分,则x不能选q[l],向上取整
    举例1: 
    以j划分时,我们盯着j看
    可证:j的最小值是l
    	证明: j的最小值是l
    	最极端的情况是只有两个数的时候
    	只有此时j能取到l
    	因为是先do,所以第一轮i肯定会来到l
    	而j无论如何通畅地往前移动都会在mid这里停一下 
    	交换之后i在第二轮会自加来到第l+1位 
    	证明完毕。 
    所以q[j+1...r]不会造成无限划分
    那么q[l...j]会出问题,因为j可能取到r
    如 2,3
    最后i和j都在3这个位置
    l~j这个子区间与l~r重合了
    无限划分出现了! 
    举例2: 
    以i划分时,i的最大值是r(和j最小是l同理)
    那么q[i,r]会出问题,因为i可能取到l(mid向下取整时)
    如2,3,mid向下取整就是2 
    最后i,j会停在2的位置 
    此时[i,r]与[l,r]重合([l,i - 1]无事)
    无限划分出现了! 
    
    数组中q[l,r-1] < x,
    那么这一轮循环结束时i = r, j = r
    下次划分就是(l,j)(j+1,r),前者即(l,r),无限循环了
     
    */
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
  • 相关阅读:
    【探索Linux世界|中秋特辑】--- 倒计时和进度条的实现与演示
    【SpringBootStarter】自定义全局加解密组件
    springcloudalibaba架构(1):如何实现服务调用Ribbon和Feign
    猿创征文|Java实现自定义注解
    未来的产品经理,需要什么样的原型设计工具?
    20230916后台面经整理
    valarray数值库学习
    学习RPA的10大理由,初学者学习RPA的几大难点!
    【前端验证】验证自动化脚本的最后一块拼图补全——gen_tb
    TypeScript24:TS中的声明文件
  • 原文地址:https://blog.csdn.net/weixin_45916959/article/details/133833432