題目:實現找中位元的中位元。
思路:自頂向下的思維方式,首先將一個長數組劃分成每5個元素為一小組的幾個小的數組,然後對每一個小的數組進行插入排序,返回第3個元素,將其儲存在一個新的數組B中,再對B進行找中位元操作,這裡並不進行排序,而是利用第9章的Select演算法,直接返回第(a+b)/2小的元素(即中位元)即可。
步驟:1將長數組劃分成小數組。
2將每個小數組進行insert_sort 操作,並將結果儲存在建立立的數組B中。
3再對B數組中的元素進行Select 中位元即可。
4Select用到partition的性質,我們知道partition的工作原理是將一個數組劃分成兩段,其中一段的元素都小於主元,另一段數組的元素都大於主元。
我們可以利用這個性質,如果主元左端和右端的元素個數都一樣,那麼主元就是中位元,我們可以改進partition,每次劃分的位置都和中位元的位置相比,遞迴向下調用, 當主元的位置等於中位元的位置時,可以返回。
代碼:
#include<iostream>#include<time.h>using namespace std;//簡單的交換void swap(int& a,int& b){if(a!=b){a^=b;b^=a;a^=b;}}//最經典樸素的劃分演算法int partition(int a[],int l,int r){int i=l;int v=a[i];//管理兩個指標i,j,j負責遍曆整個數組,i始終指向比主元小的值for(int j=l+1;j<=r;j++){//j指標向右遍曆的過程中遇到小值,都換到i位置去if (a[j]<v) {++i;if(i!=j)//可有可無,若i==j,swap(i,j)無意義swap(a[j],a[i]);}}swap(a[l],a[i]);return i;}int randdom_partition(int* A,int p,int r){int f;srand((unsigned int)time(0));f=p+rand() % (r-p+1);swap(A[f],A[p]);//用隨機數生器產生一個隨機索引,將索引指向的值和第一個值交換return partition(A,p,r);}int random_select(int* A,int p,int r,int i){int k,q;if(p==r) return A[p];q=randdom_partition(A,p,r);//隨機劃分,避免極端情況出現o(n^2),q為主元索引k=q-p+1;if(i==k)return A[q];else if(i<k)return random_select(A,p,q-1,i);else return random_select(A,q+1,r,i-k);}int insert_sort(int* a,int l, int r,int k){int i,j,key;//插入排序,依然管理兩個指標,i,j,i遍曆整個數組,j從j-1向前遍曆for( i=l+1;i<=r;i++){key=a[i];j=i-1;while(j>=l && a[j]>key)//將比key大的值後移{a[j+1]=a[j];--j;}a[j+1]=key;//插入應在的位置}return a[l+k-1];}int Find_median(int* a,int l,int r){int i,begin,end,len,key,j=0;int ret;len=r-l+1;int *B=new int[len/5+1];for(i=l;i<=r;i++){if((i-l) % 5 == 0){begin = i;}else if((i-l) % 5 == 4 || i==r){end=i;key = insert_sort(a,begin,end,(end-begin)/2 +1);//處理單個數組,找到中位元,第3個參數為返回第i個元素(從1開始),若數組為5,返回3即中位元B[j++]=key;}}ret= random_select(B, 0, j-1, (j-1)/2+1);delete []B;return ret;}void main(){int A[25];srand((unsigned int)time(0));for(int i=0;i<25;i++){A[i]=rand() % 100;if(i % 5==0)cout<<endl;printf("%3d ",A[i]);//輸出隨機產生的數組}cout<<endl;for(int i=0;i<25;i++){if(i % 5==0) insert_sort(A,i, i+4,0);}for(int i=0;i<25;i++){if(i % 5==0)cout<<endl;printf("%3d ",A[i]);//輸出排序後的數組}cout<<endl<<Find_median(A,0,24);//找出中位元的中位元}
運行結果: