使用這個演算法尋找第i小元素的最壞情況已耗用時間為O(n)。關於已耗用時間的證明簡直屌爆了!唉,看了這麼多證明,我發現其實最難的就是提出數學模型、數學描述,邁出這一步,剩下的就是湊了。
這個演算法比9.2節中那個“期望已耗用時間才是O(n)”的RandomizedPartition演算法更加牛逼,它最壞已耗用時間就是O(n)。之所以這麼屌,是因為它每次劃分都能保證是最佳劃分,即“中分”。要想實現中分,就得先把中位元找出來。
演算法find()過程如下:
(1)先把原數組a劃分成五個一組,五個一組、、、,然後對每個小組進行插入排序,得到每個小組的中位元,組成數組b。這個函數為Select()。
(2)若b元素個數不為1,則繼續對b運行步驟一。即Select()遞迴。直到找到中位元x。
(3)把中位元x作為一個參數,帶入Partition()函數,這個函數是快速排序那個劃分函數的變形。返回劃分後中位元所在的下標q。
(4)q把數組a劃分成兩部分,如果i=q-p+1,則a[q]即為第i小元素。若i<q-p+1,則i應該在低區,在低區進行遞迴find()。否則,i在高區,對高區進行遞迴find()。
代碼如下:
#include <iostream>#include <string.h>using namespace std;//對每個小組進行插入排序 void InsertionSort(int *a,int p,int r,int &mid){int i;for(int j=p+1;j<=r;j++){ i=j-1;int key=a[j];while(i>=p && a[i]>key){a[i+1]=a[i];i--;}a[i+1]=key;}int d=r-p+1;if(d%2==0){d=d/2-1;}else{d=d/2;}//cout<<d;mid=a[d+p];}//尋找數組a的中位元,放到x中void Select(int *a,int p,int r,int &x){if(p==r){x=a[p];return;}int n=r-p+1;int m=0;if(n%5==0){m=n/5;}else{m=n/5+1;}//將數組劃分為五個一組五個一組...,每一組進行插入排序,並在排序後取出每一組的中位元,放入數組b中 int b[m];int i=p;for(int j=0;j<m;j++){int mid;if(i+4<=r){InsertionSort(a,i,i+4,mid);b[j]=mid;i+=5;}else{InsertionSort(a,i,r,mid);b[j]=mid;}//cout<<"i="<<i<<" mid="<<mid<<" j="<<j<<" m="<<m<<" r="<<r;system("pause");}//對包含各分組中位元的數組b,遞迴調用Select,找出中位元xSelect(b,0,m-1,x);}//根據中位元x,對數組a進行劃分 int Partition(int *a,int p,int r,int x){int index=-1;for(int i=p;i<=r;i++){if(a[i]==x){index=i;//cout<<i;system("pause");break;}}if(index==-1){ cout<<"error"<<endl;exit(1);}int temp=a[index];a[index]=a[r];a[r]=temp;int i=p-1;for(int j=p;j<r;j++){if(a[j]<=x){i++;int tmp=a[i];a[i]=a[j];a[j]=tmp;}}int pivot=a[r];a[r]=a[i+1];a[i+1]=pivot;return i+1;}//尋找第i小的數void find(int *a,int p,int r,int i,int &result){int x;Select(a,p,r,x);//以x為主元,對數組a進行劃分int q=Partition(a,p,r,x);int k=q-p+1;if(k==i){result=a[q];}else if(k>i){find(a,p,q-1,i,result);}else{find(a,q+1,r,i-k,result);}}void Output(int *a,int n){ for(int i=0;i<n;i++) { printf("%d ",a[i]); } cout<<endl;}int main(){ int n=11; int a[n]; srand((unsigned int)time(NULL)); for(int i=0;i<n;i++) { a[i]=rand()%n; } Output(a,n);int result=-1;int i;while(1){ cout<<"輸入你要尋找的第i小:i="; cin>>i; find(a,0,n-1,i,result); cout<<"i="<<i<<" result="<<result<<endl; } //Output(a,n); system("pause"); return 0;}