AcWing 785. 快速排序(个人见解)

// 快排+选数

#include<iostream>
#include<algorithm>
using namespace std ;

const int N = 100001;
int q [N] ;

// 快排:每一层都将指定位置如pvit = (left+ right)/2 作为中心排序对象,使左边全都不大于其,右边全都不小于其,并且往左右俩边序列继续递归排序
void quick_sort (int q[], int left ,int right ){
    int base = (left+right)/2;//以base为基准
    int target = q[base];//每一轮中target都是固定值,也即分界值,分完后其左边的一定//并且这是浅拷贝,只是将q[base]值复制给target,后续如果q[r+l>>1]的值变了的话,target也不会变(如swap(q[i],q[j]),j可能是target的下标了))
    if(left >= right ) return ;//如果只剩一个或空元素,则没必要排序了
    //开始快排
    int i = left-1 , j = right+1;//左、右-1+1 为了下面的do-while更好的整体化
    while(i<j){
        do i++ ; while(q[i] < target);//找到小于q[base]的q[i]的下标i,等于是为了不会一直死循环,最差也会找到base
        do j-- ; while(q[j] > target);//找到大于其的j;j一直找比target还小的值索引,可能会过
        if(i<j) swap(q[i],q[j]);//如果找到了,并且i<j 则交换俩者
    }
    //上一层已经排完了base的位置
    quick_sort(q,left,j);//左边序列递归,如果base已经是左or右端点,则下一轮时会if(left >= right ) return ;回去
    quick_sort(q,j+1,right);//右边序列递归
}

总的来说,先从队列中随便用个数值来作为基准target。例如这里用 q[l + r >> 1]来作为该条队列的基准,一番操作后使得该选定的这个元素target= q[l + r >> 1]的左边全是不大于该元素值的数,右边全是不小于该元素值的数(也可以为空,即这个target元素被换到边界的情况:在这队列中最大or最小)。
一番操作用 i 与 j 来从该队的头、尾相向遍历,i用来找比target大的元素,j用来找比target小的元素(为了将 target 左边比target大于等于的元素 和 target右边比target小于等于的元素交换,并且这其中包括了target自身)。如 ”3 1 2 2 “ ,其中target = 1,i 会在 “3” 这里停止,等着交换,而右边的j会一直遍历到 target本身也即是“1”,此时 i < j ,满足swap条件,所以“3” 与 “1” 会交换,此时target并不会变(因为在前面target = q[ l + r >>1] 是浅拷贝,只是将该数组元素的值给了target),所以此时 为“1 3 2 2  ”, i 此时仍然停留在 “1 ” 这个索引位置 , j 仍然停留在 “3” 这个位置,所以满足while循环的条件,于是又进入循环体,此时先经历俩个do-while ,i继续++一直到找到比target大or相等的元素位置,也即是++到了第一个“2”的索引位置; j 则一直找下一个小于等于target的元素位置,也即找到了 target “1” 的索引位置,此时 i > j , 不满足swap与while了,于是略过swap,跳出while循环。 此时该条序列“3 1 2 2 ” 已经以 target = 1 为基准 ,分为了“1 3 2 2”, 基准左边没有比自身大的数,基准右边没有比基准更小的数,即完成了 基准target的排序位置。进入下一层序列开始排序( 即q[ left , j ] ,q[ j+1 , right ]俩条左右序列,以 j 为分界值是因为j最后是在小于等于target处停下来的,从最右端走到现在已经将小于等于target的值给换到target左边去了,所以自然q[left, j ] 与 q[j+1 , right ]被分成了 一个不大于target的左序列,一个不小于target的右序列) ,所以一直递归下去排序。

另外附上y总的快排模板:
 

#include <iostream>

using namespace std;

const int N = 100010;

int q[N];

void quick_sort(int q[], int l, int r)
{
    if (l >= r) return;

    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while (i < j)
    {
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    }

    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);
}

int main()
{
    int n;
    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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值