分治 - 快排 + 快选

分治 - 快排 + 快选

快排模板:

#include <iostream>

using namespace std;
const int N=1e5+10;

int n,a[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()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    quick_sort(a,1,n);
    
    for(int i=1;i<=n;i++) cout<<a[i]<<" ";
    
    return 0;
}

快速选择算法:

选 择 长 度 为 n 的 序 列 中 第 k 小 的 数 。 理 论 时 间 复 杂 度 O ( n ) 。   实 现 步 骤 与 快 排 类 似 : ① 、 选 择 一 个 基 准 x , 将 序 列 分 成 < = x 的 左 半 部 分 和 > = x 的 右 半 部 分 。   ② 、 假 设 左 半 部 分 由 S l 个 数 , 若 k < = S l , 那 么 说 明 第 k 小 的 数 在 左 半 区 间 , 否 则 在 右 半 区 间 。 但 是 需 要 注 意 的 是 , 若 在 右 半 区 间 , 整 个 序 列 第 k 小 的 数 应 当 是 右 半 区 间 k − S l 小 的 数 。   这 样 , 每 层 递 归 需 要 计 算 的 次 数 就 是 该 层 序 列 的 长 度 , 与 快 排 不 同 的 是 , 每 次 仅 需 选 择 一 个 分 支 。 总 的 平 均 计 算 次 数 T ( n ) = n + n 2 + n 4 + . . . = n ( 1 + 1 2 + 1 4 + . . . ) < = 2 n , 故 时 间 复 杂 度 是 O ( n ) 的 。 选择长度为n的序列中第k小的数。理论时间复杂度O(n)。\\ \ \\实现步骤与快排类似:\\①、选择一个基准x,将序列分成<=x的左半部分和>=x的右半部分。\\ \ \\②、假设左半部分由S_l个数,若k<=S_l,那么说明第k小的数在左半区间,否则在右半区间。\\但是需要注意的是,若在右半区间,整个序列第k小的数应当是右半区间k-S_l小的数。\\ \ \\这样,每层递归需要计算的次数就是该层序列的长度,与快排不同的是,每次仅需选择一个分支。\\总的平均计算次数T(n)=n+\frac{n}{2}+\frac{n}{4}+...=n(1+\frac{1}{2}+\frac{1}{4}+...)<=2n,故时间复杂度是O(n)的。 nkO(n) x<=x>=x Slk<=SlkkkSl T(n)=n+2n+4n+...=n(1+21+41+...)<=2nO(n)

例题:

给定一个长度为n的整数数列,以及一个整数k,请用快速选择算法求出数列的第k小的数是多少。

输入格式
第一行包含两个整数 n 和 k。

第二行包含 n 个整数(所有整数均在1~109范围内),表示整数数列。

输出格式
输出一个整数,表示数列的第k小数。

数据范围
1≤n≤100000,
1≤k≤n

输入样例:
5 3
2 4 1 5 3
输出样例:
3

代码:

#include<iostream>

using namespace std;

const int N=1e5+10;
int n,k,a[N];

int quick_sort(int l,int r,int k)
{
    if(l==r) return a[l];
    
    int i=l-1,j=r+1,x=a[l+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]);
    }
    
    int sl=j-l+1;
    if(k<=sl) return quick_sort(l,j,k);
    else return quick_sort(j+1,r,k-sl);
}

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    cout<<quick_sort(1,n,k)<<endl;
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值