|举报|字号 订阅
http://ds.fzu.edu.cn/fine/resources/FlashContent.asp?id=82
然后还是讲讲算法吧:
终止条件:n=1时,返回的即是i小元素。
算法步骤:
step1:将n个元素每5个一组,分成n/5(上界)组。
step2:取出每一组的中位数,任意排序方法,比如插入排序。
step3:递归的调用selection算法查找上一步中所有中位数的中位数,设为x,偶数个中位数的情况下设定为选取中间小的一个。
step4:用x来分割数组,设小于等于x的个数为k,大于x的个数即为n-k。
step5:若i==k,返回x;若i<k,在小于x的元素中递归查找第i小的元素;若i>k,在大于x的元素中递归查找第i-k小的元素。
简单的分析:在第三步选出x时,大于x的元素至少有3n/10 – 6个,在最差的情况下,第五步递归作用的元素个数是7n/10 + 6.可得递归表达式如下:
T(n) <= T(n/5) + T(7n/10 + 6) + O(n)
原理和快速选择选择类似
类似快排中的分割算法:
每次分割后都能返回枢纽点在数组中的位置s,然后比较s与k的大小
若大的话,则再次递归划分array[s..n],
小的话,就递归array[left…s-1] //s为中间枢纽点元素。
否则返回array[s],就是partition中返回的值。 //就是要找到这个s。
找到符合要求的s值后,再遍历输出比s小的那一边的元素。
【题目】:给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素,(这里给定的线性集是无序的) 【思路】:如果能在线性时间内找到一个划分基准,使得按这个基准所划分出的2个子数组的长度都至少为原数组长度的ε倍(0<ε<1是某个正常数),那么就可以在最坏情况下用O(n)时间完成选择任务。 【具体解题】:这里我们将所有的数(n个),以每5个划分为一组,共[n/5]组(将不足五个的那组忽略);然后用任意一种排序算法(因为只对五个数进行排序,所以任取一种排序法就可以了,这里我选用冒泡排序),将每组中的元素排好序再分别取每组的中位数,得到[n/5]个中位数;再取这[n/5]个中位数的中位数(如果n/5是偶数,就找它的2个中位数中较大的一个)作为划分基准,将全部的数划分为两个部分,小于基准的在左边,大于等于基准的放右边。 #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); |