1. 问题
给定数组,找出数组中第k小的元素。
2. 解析
先是简单的分治思想:
随便取数组中的一个数作为基准,按照快排思想,小于这个数的放在他的前面,随后比较这个数的下标和k的值决定,两者相等该值即为k小值,否者>时分治查找前半部分,<时查找后半部分;
这个样子复杂度最坏可能到达n^2
随后我们深入,通过巧妙的方式选取这个基准提高效率:
将数组划分,5个一组,不足的舍掉:
计算每组的中值存为s,计算s的中值。将这个中值作为基准,这时重复上面的分治,效率便可以明显提高;
3. 设计
伪函数:
Aaa(int p[],int l,int r)//查找中值函数,返回中值坐标
{
插入排序
}
Bbb(int p[],int l,int r)//返回中位数的中位数
{
If(r-l<5)aaa(p,l,r);
Else{
Return Ccc(p,l,r,(l+r)/2);
}
}
Ccc(int p[],int l,int r,int k){//求第k小函数
Date=(r-l)/5;
Sss=l;
For(i=0;i<date;i++){
J=Aaa(p,l+(i*5), l+(i*5))
Swap(p[sss++],p[j]);
}
Sss=Bbb(p,l,l+date);
整理数组,小于p[Sss]的交换到他前面,大于等于的放到后面;
If((Sss+1)==k)return p[Sss];
Else if(Sss+1>k)return Ccc(p,l,Sss-1,k);
Else return Ccc(p,Sss+1,r,k-Sss-1)
}
Main(){
输入数据存p[],输入k;
调用Ccc并输出;
}
4. 分析
时间复杂度T[n]=O(nlogn)
选出n/5个中位数,中位数的中位数大于1/2的中位数,即大于3*(1/2)*(n/5)=3n/10的数,最坏的情况递归选择到7n/10那部分,即复杂度T(n)
有
因此T(n)=O(n)
5. 源码
https://github.com/Bcxx/task_code/tree/master/BFPRT