仔细分析下y总提到但没细讲原理的内容,深化细节理解和数据处理全局了解
算法基础课一:快速排序 —— 1边界点选取与死循环 2 l-1和r+1的原因
一、死循环1:边界点下标为l(或r),分段为(l,i-1),(i,r)(或(1,j)与(j+1,r))
验算算法可知,每轮指针移动中i(或l)将保持不变。
若以q[l]为分界点,每轮指针移动结束后i仍然为r。
对于q[N]中一个顺序段,每轮移动后j收缩到l,划分后的两段:(l,i-1)=(l,l-1)判为空段,(i,r)=(l,r)循环
二、死循环2:分界点不为(l+r)/2,遇到偶然情况[i,j]初始左右元素相同
验算可知,每轮循环[i,j]两段元素交换位置,构成死循环。
这也是数据增强后破解死循环1无法通过的原因。
三、死循环3:分界点为(l+r+1)/2
可能造成取到边界,(处理段长度为2时)形成死循环1。
这是种偶然情况,Acwing中分界点取(l+r+1)/2不通过,但取(l+r-1)则通过。
四、边界先l-1,r+1的原因
先扩大,而后缩小为有效区间。
为进行比较,确保开启递归的原始段非空从而能开启递归循环,使得交换元素的循环初始有效,即使实际有效段元素仅仅一个,其开启递归的原始段可能不止一个,因而可以进行下一轮递归,而后通过循环后将区间长为一的元素返回。
int i = l - 1, j = r + 1;
while(i < j){
i++; while(q[i] < x) i++;
j--; while(q[j] > x) j--;
------
五、促背模板
#include<iostream>
const int N = 1e6 + 10;
int n;
int q[N];
// 递归基判断l>=r
// 快排三步:分界点,排序调整=边界收缩与交换,分段递归循环
void quick_sort(int q[], int l, int r)
{
if(l >= r) {return;}
int x = q[(l + r)/2];
int i = l - 1, j = r + 1;
while(i < j){
i++ ; while(q[i] < x) i++;
j++ ; while(q[j] > x) j++;
if(i < j) swap(q[i], q[j]);
}
quick_sort(q, l, i-1);
quick_sort(q, i, r);
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; i++){ scanf("%d", &q[i])}
quick_sort(q, 0, n - 1);
for(int i = 0; i < n; i++){ printf("%d ", q[i])}
return(0);
}