問題描述:給一個無序數組,找到其中位數,並說出該算法的時間復雜度以及空間復雜度。
解題方法一:
中位數:當數組元素個數為奇數n時,中位數=a[n/2]。當元素個數為偶數時,中位數=( a[n / 2] + a[ ( n + 1 ) / 2 ])
按照這個中位數定義來求解。利用快速排序對數組進行排序,時間復雜度為O(nlogn) 空間復雜度為S(1); 之后的找到中位數所用時間復雜度為O(1) 空間復雜度為O(1)
解題方法二:
在了解方法二之前我們先來了解一下快速排序。對於快排算法,其中主元的選擇對於數組的划分起到很大的影響,從而對於運行時間產生很大的影響。當主元不能很好地分割數組,即主元將數組分成一個子數組中有一個記錄,而另一個子組組有 n -1 個記錄時,下一次的子數組只比原來數組小 1,這是快速排序的最差的情況。如果這種情況發生在每次划分過程中,那么快速排序就退化成了冒泡排序,其時間復雜度為O(n2)。老師曾經舉過一個例子:甲、乙兩同學去比較各自排序算法的好壞,他們可以互相閱讀對方的原代碼,然后互相給對方提供無序數組,最后比較那個運行比較快。乙同學看到甲同學的快排的代碼,乙同學針對甲同學的代碼專門寫了所謂的無序數組(並非無序數組,只是甲同學的代碼在解決這個無序數組的排序中會退化成冒泡排序)。然而甲同學看到乙同學的快排代碼之后就老老實實的給了無序數組。為什么甲同學沒有去找針對於乙同學的那個能夠導致退化的無序數組呢?原因就是乙同學的快排主元的選擇是隨機化的。
隨機化排序代碼:

1 #include<stdio.h> 2 #include<stdlib.h> 3 int partition(int *a,int p,int r); 4 int random_partition(int *a,int p,int r); 5 int random_select(int *a,int p,int r,int i); 6 int main() 7 { 8 9 system("pasue"); 10 return 0; 11 } 12 int partition(int *a,int p,int r) 13 { 14 int x=a[r],t; 15 int i=p-1,j; 16 for(j=p;j<=r-1;j++) 17 { 18 if(a[j]<=x)//如果要降序排列,則改為if(a[j]>=x) 19 { 20 i++; 21 t=a[i]; 22 a[i]=a[j]; 23 a[j]=t; 24 } 25 } 26 t=a[i+1]; 27 a[i+1]=a[r]; 28 a[r]=t; 29 return i+1; 30 } 31 int random_partition(int *a,int p,int r) 32 { 33 int t,i; 34 i=p+(int)((r-p+1)*rand()/(RAND_MAX+1.0));//利用隨機數隨機選擇用於分割的元素,注意范圍 35 t=a[i]; 36 a[i]=a[r]; 37 a[r]=t; 38 return partition(a,p,r); 39 } 40 int random_select(int *a,int p,int r,int i)//找出a[p]——a[r]之間第i小的元素 41 { 42 int q; 43 if(p==r) 44 return a[p]; 45 q=random_partition(a,p,r); 46 int k=q-p+1; 47 if(i==k) 48 return a[q]; 49 else if(i<k) 50 return random_select(a,p,q-1,i); 51 else 52 return random_select(a,q+1,r,i-k); 53 }
線性時間選擇算法:
含義:是解決選擇問題的分治算法
與快速排序不同的是:快排遞歸處理划分的兩邊,而線性選擇只對其中
的一個部分進行處理
時間復雜度:O(n)
實現:需要用到隨機划分函數
主要的過程好似:A[p...r]通過隨機划分函數得到樞軸q
根據划分的兩個區間A[p...q-1],A[q],A[q+1...r]
然后判斷<=A[q]的元素數量k=q-p+1 與 需要尋找的第i小的關系
如果 k == i,直接返回A[q]
如果 k > i,說明第i小的元素只可能在區間A[p...q-1]中
如果 k < i ,說明第i小的元素在區間A[q+1...r]中 ,並且問題轉化為在A[q+1...r]中尋找第i-k小的元素
參考代碼:

1 #include <iostream> 2 #include <stdlib.h> 3 #include <stdlib.h> 4 5 using namespace std; 6 7 //返回iMin~iMax中的任意數字 8 int myrandom(int iMin,int iMax) 9 { 10 // 3~6,6-3=3 , 11 int iResult = rand() % (iMax - iMin + 1) + iMin; 12 return iResult; 13 } 14 15 void swap(int* pArr , int p , int q) 16 { 17 int iTemp = pArr[p]; 18 pArr[p] = pArr[q]; 19 pArr[q] = iTemp; 20 } 21 22 int randomPartition(int* pArr,int iLow ,int iHigh) 23 { 24 int iRand = myrandom(iLow , iHigh); 25 swap(pArr , iRand , iLow); 26 int iPivot = pArr[iLow]; 27 //下面就是快排的樞軸划分 28 while(iLow < iHigh) 29 { 30 while(iLow < iHigh && pArr[iHigh] >= iPivot) 31 { 32 iHigh--; 33 } 34 pArr[iLow] = pArr[iHigh]; 35 while(iLow < iHigh && pArr[iLow] <= iPivot) 36 { 37 iLow++; 38 } 39 pArr[iHigh] = pArr[iLow]; 40 } 41 pArr[iLow] = iPivot; 42 return iLow; 43 } 44 45 int randomizedSelect(int* pArr,int p ,int r,int i) 46 { 47 if(p == r) 48 { 49 return pArr[p]; 50 } 51 int q = randomPartition(pArr, p ,r); 52 int k = q - p + 1; 53 if(i == k) 54 { 55 return pArr[q]; 56 } 57 //在低區間 58 else if(i < k) 59 { 60 int iResult = randomizedSelect(pArr, p , q-1 ,i); 61 return iResult; 62 } 63 else 64 { 65 int iResult = randomizedSelect(pArr , q + 1 , r , i - k); 66 return iResult; 67 } 68 } 69 70 void process() 71 { 72 int n,u; 73 while(cin >> n >> u) 74 { 75 int* pArr = new int[n]; 76 for(int i = 0; i < n ; i++) 77 { 78 cin >> pArr[i]; 79 } 80 int iResult = randomizedSelect(pArr, 0 , n -1 , u); 81 cout << iResult << endl; 82 delete[] pArr; 83 } 84 } 85 86 int main(int argc,char* argv[]) 87 { 88 process(); 89 getchar(); 90 return 0; 91 }