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