找出N個整數中最大的K個數
阿新 • • 發佈:2019-02-04
《尋找N個元素中的前K個最大者》方法總結是在這裡看到的 /algorithm/20111105/314362.html ,我覺得解法二和解法四用得廣泛一些,程式設計實現了一下。
利用快速排序中的partition操作
經過partition後,pivot左邊的序列sa都大於pivot右邊的序列sb;
如果|sa|==K或者|sa|==K-1,則陣列的前K個元素就是最大的前K個元素,演算法終止;
如果|sa|<K-1,則從sb中尋找前K-|sa|-1大的元素;
如果|sa|>K,則從sa中尋找前K大的元素。
一次partition(arr,begin,end)操作的複雜度為end-begin,也就是O(N),最壞情況下一次partition操作只找到第1大的那個元素,則需要進行K次partition操作,總的複雜度為O(N*K)。平均情況下每次partition都把序列均分兩半,需要log(2,K)次partition操作,總的複雜度為O(N*log(2,K))。
#include<iostream> |
#include<cstdlib> |
#include<ctime> |
#include<vector> |
#include<algorithm> |
using namespace std; |
/*分割,pivot左邊的都比右邊的大*/ |
template < typename Comparable> |
int partition(vector<Comparable> &a, int left, int right){ |
int begin=left; |
int end=right; |
Comparable pivot=a[left]; |
while (left<right){ |
while (left<right && a[right]<=pivot) |
right--; |
a[left]=a[right]; |
while (left<right && a[left]>=pivot) |
left++; |
a[right]=a[left]; |
} |
a[left]=pivot; |
return left-begin; //返回pivot左邊的元素個數 |
} |
template < typename Comparable> |
void findKMax(vector<Comparable> &vec, int left, int right, int k){ |
if (k>right-left+1) |
return ; |
//由於partition時,總是固定地選取首元素作為軸,所以事先打亂一下順序比較好,防止演算法退化 |
//random_shuffle(vec.begin()+left,vec.begin()+right); |
int n=partition(vec,left,right); |
if (n==k || n==k-1) |
return ; |
if (n<k-1) |
findKMax(vec,left+n+1,right,k-n-1); |
else if (n>k) |
findKMax(vec,left,left+n-1,k); |
} |
int main(){ |
int total=5; //原先有5個元素 |
int k=3; //選取前3個最大的 |
srand ( time (0)); |
vector< int > a(total); |
for ( int i=0;i<a.size();i++) |
a[i]= rand ()%100; |
for ( int i=0;i<a.size();i++) |
cout<<a[i]<< "\t" ; |
cout<<endl; |
findKMax(a,0,a.size()-1,k); |
for ( int i=0;i<a.size();i++) |
cout<<a[i]<< "\t" ; |
cout<<endl; |
return 0; |
} |
利用小根堆實現
順序讀取陣列中的前K個元素,構建小根堆。小根堆的特點是根元素最小,並且一次調整(deleteMin)操作的時間複雜度為log(2,K)。
接下來從陣列中取下一個元素,如果該元素不比堆頂元素大,則丟棄;否則用它替換堆頂元素,然後調整小根堆。
當把陣列中的元素全部讀出來後,小根堆中保留的就是前K大的元素。
初始建堆操作需要K*log(2,K)--這是最多的操作次數,從陣列中讀取後N-K個元素和堆頂元素一一比較,最壞的情況是每次都要替換堆頂元素,都要調整小根堆,複雜度為(N-K)*log(2,K)。總的複雜度為O(N*log(2,K))。
#include<iostream> |
#include<cstdlib> |
#include<ctime> |
#include<vector> |
using namespace std; |
template < typename Comparable> |
void percolate(vector<Comparable> &vec, int index){ |
int i=index; |
int j=2*i+1; |
while (j<=vec.size()){ |
if (j<vec.size() && vec[j]>vec[j+1]) |
j++; |
if (vec[i]<vec[j]) |
break ; |
else { |
swap(vec[i],vec[j]); |
i=j; |
j=2*i+1; |
} |
} |
} |
template < typename Comparable> |
void buildHeap(vector<Comparable> &vec){ |
int len=vec.size(); |
for ( int i=(len-1)/2;i>=0;i--) |
percolate(vec,i); |
} |
int main(){ |
srand ( time (0)); |
vector< int > a(10); //原先有10個元素 |
for ( int i=0;i<a.size();i++) |
a[i]= rand ()%100; |
vector< int > b(7); //找出a中最大的前7個元素 |
for ( int i=0;i<b.size();i++) |
b[i]=a[i]; |
buildHeap(b); |
for ( int i=b.size();i<a.size();i++){ |
if (a[i]>b[0]){ |
b[0]=a[i]; |
percolate(b,0); |
} |
} |
vector< int >::iterator iter=a.begin(); |
while (iter!=a.end()){ |
cout<<*iter<< "\t" ; |
iter++; |
} |
cout<<endl; |
iter=b.begin(); |
while (iter!=b.end()){ |
cout<<*iter<< "\t" ; |
iter++; |
} |
cout<<endl; |
return 0; |
} |