最坏情况线性时间选择O(n)

来源:互联网 发布:ims注册成功率优化 编辑:程序博客网 时间:2024/05/22 14:01

题目】:给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素,(这里给定的线性集是无序的)

思路】:如果能在线性时间内找到一个划分基准,使得按这个基准所划分出的2个子数组的长度都至少为原数组长度的ε倍(0<ε<1是某个正常数),那么就可以在最坏情况下用O(n)时间完成选择任务。
例如:若ε=9/10,算法递归调用所产生的子数组的长度至少缩短1/10。所以,在最坏情况下,算法所需的计算时间T(n)满足递归式T(n)≤T(9n/10)+O(n) 。由此可得T(n)=O(n)。

具体解题】:这里我们将所有的数(n个),以每5个划分为一组,共[n/5]组(将不足五个的那组忽略);然后用任意一种排序算法(因为只对五个数进行排序,所以任取一种排序法就可以了,这里我选用冒泡排序),将每组中的元素排好序再分别取每组的中位数,得到[n/5]个中位数;再取这[n/5]个中位数的中位数(如果n/5是偶数,就找它的2个中位数中较大的一个)作为划分基准,将全部的数划分为两个部分,小于基准的在左边,大于等于基准的放右边。
    在这种情况下,找出的基准x至少比3(n-5)/10个元素大,因为在每一组中有2个元素小于本组的中位数,中位数处于1/2*[n/5-1],即n/5个中位数中又有(n-5)/10个小于基准x。同理,基准x也至少比3(n-5)/10个元素小。而当n≥75时,3(n-5)/10≥n/4所以按此基准划分所得的2个子数组的长度都至少缩短1/4。
程序代码如下:

#include<iostream.h>

#include<stdlib.h>

#include<time.h>

#define MAX_VALUE 10000

#define random() rand()%MAX_VALUE

#define N 10000

int a[N];

class Find

{

public:

       void bubble(int first,int end) //冒泡排序

       {    

for(int flag=first;flag<end;flag++)

                     for(int i=end;i>flag;i--)

                            if(a[i]<a[i-1])

                            {     int t=a[i];

                                   a[i]=a[i-1];

                                   a[i-1]=t;

                            }

       }

       int partition(int p,int r,int x) //数组a中从a[p]a[r]的元素按照x划分,大于x的在左边,小于x的在右边

       { 

 int i,j;

              for(i=p,j=r;i<j;i++)

              {    

if(a[i]>x)

                     {    

while(i<j&&a[j]>x)

                                   j--;

                            if(i!=j){

                                   int t=a[i];

                                   a[i]=a[j];

                                   a[j]=t;

                                   j--;

                            }

                     }

              }

              return i-1;

       }

       int select(int p,int r,int k)   //寻找中位数

       {

              if(r-p<5){

                     bubble(p,r);

                     return a[p+k-1];

              }

              for(int i=0;i<(r-p-4)/5;i++)

              {

                     int s=p+5*i,t=s+4;

                     bubble(s,t);

                     int temp=a[p+i];

                     a[p+i]=a[s+2];

                     a[s+2]=temp;

              }

              int x=select(p,p+(r-p-4)/5,(r-p+6)/10);

              i=partition(p,r,x);

              int j=i-p+1;

              if(k<=j)

                     return select(p,i,k);

              else

                     return select(i+1,r,k-j);

       }

};

void main()

{

       clock_t   start,end;  

       double   elapsed;

       srand((int)time(NULL));

       for(int k=0;k<N;k++)

       {

              a[k]=random();

              cout<<a[k]<<"/t";

       }

       cout<<endl;

       start=clock();

       Find f;    

       int n=5000;

       cout<<"The No."<<n<<" is :"<<f.select(0,N-1,n)<<endl;

       end=clock();

       elapsed=((double)(end-start));///CLOCKS_PER_SEC;

       cout<<"Time: "<<elapsed<<endl;

}

这个题目关键在寻找划分基准,从而提高寻找效率,时间复杂度为o(n);
本文固定链接为:http://www.hinn.cn/2008/04/randomizedselect.html

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 学校退款卡丢了怎么办 学校发的卡掉了怎么办 汇款回执单丢了怎么办 大学交学费的卡丢了怎么办 交学费的银行卡丢了怎么办 学校补助卡丢了怎么办 学校交学费的卡丢了怎么办 采购零星材料无发票怎么办 租房合同弄丢了怎么办 买房的合同丢了怎么办 押金的收据丢了怎么办 房东的合同掉了怎么办 个人档案里单位没有放合同怎么办 签的合同掉了怎么办 一方合同弄丢了怎么办 合同丢了怎么办如何补 签了定金合同对方违约怎么办 医学出生证明丢了怎么办 易通行出站未刷怎么办 炭烧酸奶过期了怎么办 西安建行etc坏了怎么办 电机在设备壳体中拔不出来怎么办 公司变更股东不能亲临现场怎么办? 公司股东变更老股东不签字怎么办 公司变更地址股东不签字怎么办 公司变更股份股东不签字怎么办 公司股东离职股东没变更过来怎么办 河南省宋基投资公司欠钱怎么办 曲江楼观2O18怎么办 华旭金卡身份证扫描不了怎么办 水表里有钱没水怎么办? ff14过图速度慢怎么办 想让电表跑的慢怎么办 家里电表突然没有电了怎么办 电表不识别电卡怎么办 家里水表不转了怎么办 车管所体检色弱怎么办 煤气押金单没了怎么办 中国建设银行登录密码忘了怎么办 中国建设银行登录密码忘记了怎么办 公司车辆怎么办换新能源牌