AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

快速排序的灵活运用

作者: 作者的头像   zzw1 ,  2019-10-11 20:42:07 ,  所有人可见 ,  阅读 2152


8


11

这次分享来源于群友分享头条面试经历,其中有一题内容是关于快速排序的灵活运用,快排边界问题有点烦 水个博客

谢谢 @猛虎嗅蔷薇 同学

问题是:在 $ O(n) $ 的时间复杂度,$ O(1) $ 的空间复杂度内将只含有0,1,2三种数的数组排序

先上y总快速排序模板

时间复杂度 $ O(nlong(n)) $
空间复杂度 $ O(1) $

//这里填你的代码^^
//注意代码要放在两组三个点之间,才可以正确显示代码高亮哦~
#include <iostream>

using namespace std ;

const int N = 100010 ;

int a[N] ;
int n ;

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


int main(){
    scanf("%d",&n) ;

    for(int i=0;i<n;i++){
        scanf("%d",&a[i]) ;
    }
    int l=0,r=n-1 ;

    quick_sort(a,0,n-1) ;

    for(int i=0;i<n;i++){
        printf("%d ",a[i]) ;
    }
    return 0 ;
}

彩虹快速排序(即数组中只有k种数) 一开始想用二分的,时间复杂度超了,也记录一下,当作笔记

时间复杂度 $ O(nlong(k)) $
空间复杂度 $ O(1) $

#include <iostream>

using namespace std ;

const int N = 100010 ;

int a[N] ;

void quick_sort(int a[],int l,int r,int from,int to){
    if(l>=r || from == to){//当数组中只有一种颜色时或左边界超过右边界时返回
        return ;
    }
    int x = (from+to)/2,i=l,j=r ;
    while(i<j){
        while(i<j && a[i]<=x){
            i++ ;
        }
        while(i<j && a[j]>x){
            j-- ;
        }
        if(i<j){
            swap(a[i],a[j]) ;
            i++ ;
            j-- ;
        }
    }
    quick_sort(a,l,j,from,x) ;
    quick_sort(a,j+1,r,x+1,to) ;
}

int main(){
    int n ;
    scanf("%d",&n) ;
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]) ;
    }
    quick_sort(a,0,n-1,0,3) ;
    for(int i=0;i<n;i++){
        printf("%d ",a[i]) ;
    }
    return 0 ;
}

荷兰国旗问题

正确解法: 思路也是分治,将数组中大于分割值的数放右边,小于的放左边,等于的放中间

时间复杂度 $ O(n) $
空间复杂度 $ O(1) $

void quick_sort(int a[],int l,int r){
    int i = l-1 ;//左边界
    int j = r+1 ;//右边界
    while(l<j){
        if(a[l]<1){
            swap(a[++i],a[l++]) ;
        }else if(a[l]>1){
            swap(a[l],a[--j]) ;
        }else{
            l++ ;
        }
    }
}

12 评论


用户头像
孤独时代的罗永浩   2020-07-20 03:55         踩      回复

一直搞不明白为什么 i = l-1 之后再 do i++, 先退一个1再加1是有啥特殊含义吗,直接 i = l, while*** 不可以吗

用户头像
沐小锦   2020-10-05 14:46         踩      回复

同问

用户头像
zzw1   2020-10-05 16:26    回复了 沐小锦 的评论         踩      回复

这样的做法可以避免当两个指针的值等于分割值是陷入死循环,利用先加的方式,直接跳过,每次递归处理后得到的一部分是小于等于分割值的,另一部分是大于等于分割值的。

用户头像
沐小锦   2020-10-10 10:51    回复了 zzw1 的评论         踩      回复

懂了!谢谢大佬


用户头像
ChinaPie   2019-10-31 00:07         踩      回复

请问彩虹快排是在哪里看到的呢? 网上搜不到

用户头像
zzw1   2019-10-31 00:25         踩      回复

搜彩虹排序,可以搜到的


用户头像
zzw1   2019-10-11 20:45         踩      回复

y总啥时侯上线@功能可以提醒人看?@yxc hh

用户头像
yxc   2019-10-11 23:04         踩      回复

收到,已加入需求列表

用户头像
zzw1   2019-10-11 23:27    回复了 yxc 的评论         踩      回复

👍

用户头像
CiaoQJ   2020-10-19 21:39    回复了 yxc 的评论         踩      回复

Y总 其实我一直好奇 如果两指针相遇 的情况, 我的算法书上是相遇不满足条件 停下来 ,CSDN上是 两指针相遇后 有一个判断 如果两指针同时指的数A大于 X(x是分区间的那个数) A与X要交换 所以在你的模板里 两个指针相遇之后 是啥情况

用户头像
yxc   2021-02-04 02:03    回复了 CiaoQJ 的评论         踩      回复

相遇之后[l, j]的所有元素小于等于x,[j + 1, r]的所有元素大于等于x。

用户头像
winQueen   2021-06-22 18:42    回复了 yxc 的评论         踩      回复

y总,为什么在写判断的时候如果把小于大于改成小于等于大于等于就无法通过呀,查了一下是因为相同元素不交换导致快排的时间上升了吗?可是为什么会这样呢


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息