- 遇到題目為從n個無序數組中找出第K大的數,最開始想到的就是冒泡排序、選擇排序等,每次找到一個最大(或最小)的,但是很明顯需要時間復雜度為O(n*k)!具體代碼細節參考findK_2
- 改進一點的算法有根據快速排序的思想,時間復雜度達到O(n)。想象一下,第k大,說明前面有k-1個元素是比第k個元素大,那么利用快速排序的思想,將大於軸值(暫且固定第一個元素)的放在左邊,小於軸值的放在右邊。那么一趟划分下來,如果左邊的元素數目大於k,那么則說明下一趟繼續在左邊進行划分;相反,則一趟繼續在右邊進行划分...直到划分軸索引等於k。具體代碼細節參考findK_1(想一想,划分軸索引為k的時候,根據快速排序划分的思想,是不是前面有k-1個比它大的數,那么是不是找到了第k大的數?)
- 當內存中不能一次性存下很多數的時候,O(n)的算法就不能滿足需求了,這時候有O(nlogk)的算法,即根據堆排序的思想,建立一個k的元素的大根堆,遍歷整個數組,不斷調整並輸出。具體代碼細節參考findK_3
/***************** n個無序數中求第K大數 *****************/ #include<iostream> #include<cstdio> #include<algorithm> using namespace std; /*冒泡排序思想,時間復雜度:O(n*k)*/ int findK_2(int a[], int k){ bool flag = true; for(int i=0;i<k && flag;i++){ flag=false; for(int j=8;j>i;j--){ if(a[j]>a[j-1]){ swap(a[j],a[j-1]); flag=true; } } } return a[k-1]; } /*堆排序思想,時間復雜度:O(nlogk) */ //將a[s...m]調正為堆,其中除s位置值都符合堆定義 void AdjustHeap(int a[], int s, int m){ int j, tmp=a[s]; for(j=s*2;j<=m;j*=2){ if(j<m && a[j]<a[j+1]){ ++j; } if(a[j]<=tmp){ break; } a[s]=a[j]; s=j; } a[s]=tmp; } int findK_3(int a[], int k){ int len = 9; //建堆 for(int i=(len-1)/2;i>=0;i--){ AdjustHeap(a, i, len-1); } //堆排序 for(int i=len-1;i>=len-k;i--){ swap(a[i], a[0]); AdjustHeap(a, 0, i-1); } return a[len-k]; } /*快速排序思想,時間復雜度:O(n) */ int Partition(int low, int high, int a[]){ int p = a[low]; //哨兵 while(low<high){ while(low<high && a[high]<=p){ high--; } a[low]=a[high]; while(low<high && a[low]>p){ low++; } a[high] = a[low]; } a[low] = p; return low; } int findK_1(int a[], int k, int low, int high){ int tmp = Partition(low, high, a); if(tmp==k-1){ return a[tmp]; }else if(tmp>k-1){ findK_1(a, k, low, tmp-1); }else{ findK_1(a, k, tmp+1, high); } } int QuickSort(int a[], int low, int high){ if(low<high){ int tmp = Partition(low, high, a); QuickSort(a, low, tmp-1); QuickSort(a, tmp+1, high); } } int main(){ int a[] = {15,3,2,6,1,10,13,11,8}; int b[] = {15,3,2,6,1,10,13,11,8}; int c[] = {15,3,2,6,1,10,13,11,8}; int d[] = {15,3,2,6,1,10,13,11,8}; int k; cout<<"輸入k: "; cin>>k; QuickSort(a, 0, 8); cout<<"快速排序后:"<<endl; for(int i=0;i<=8;i++){ printf("%d%c",a[i],i!=8?' ':'\n'); } int big_k_1 = findK_1(b, k, 0, 8); printf("利用快速排序思想O(n),第%d大的數為:%d\n", k, big_k_1); int big_k_2 = findK_2(c, k); printf("利用冒泡排序思想O(n*k),第%d大的數為:%d\n", k, big_k_2); int big_k_3 = findK_3(d, k); printf("利用堆排序思想O(nlogk),第%d大的數為:%d\n", k, big_k_3); return 0; }
代碼運行如下:
輸入k: 3 快速排序后: 15 13 11 10 8 6 3 2 1 利用快速排序思想O(n),第3大的數為:11 利用冒泡排序思想O(n*k),第3大的數為:11 利用堆排序思想O(nlogk),第3大的數為:11