好了,断续微软面试题的学习!看到题目,我首先想到的是树状数组,后来看PPT才发现用树状数组可以实现查找第k大的元素,细想一下和这道题也差不多。网上的很多实现都是用堆做的,用堆大多数也是用C++的STL,Multiset来实现。网上代码很多,而且我也没弄明白这题,先就不自己写代码了。
在这里,给出一个O(n)复杂度的实现:BFPRT算法。我也是才看到的,觉得很好,就先保存下来。申明一下,暂时用的是别人的代码.
关于BFPRT算法,可以参考下面的链接:
http://zhulinb123.blog.163.com/blog/static/184414043201110111611859/
http://ds.fzu.edu.cn/fine/resources/FlashContent.asp?id=82
第二个链接是一个flash动画,做得非常好!能让人很清晰地看到这个算法的执行过程。好了,还是把代码贴出来吧!
- /*
- * Problem_5.cpp
- *寻找最小的K个数
- * Created on: 2012-8-29
- * Author: Administrator
- */
- #include<iostream.h>
- #include<stdlib.h>
- #include<time.h>
- #define MAX_VALUE 10000
- #define random() rand()%MAX_VALUE
- #define N 10
- 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) //寻找中位数
- { int i;
- if(r-p<5){
- bubble(p,r);
- return a[p+k-1];
- }
- for(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);
- }
- };
- int 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=4;
- 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;
- cout<<"最小的"<<n<<"个元素为:"<<endl;
- for(int k=0;k<n;k++){
- cout<<a[k]<<"\t";
- }
- return 0;
- }