[题] 快速排序 #分治

题目

快速排序


题解

边界问题很麻烦
参考博客


代码

#include <iostream>
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<j
    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),无限循环了
 
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值