一列數中尋找最大K個數。算法
【思路】api
1.常規思路,排序,數前K個數。缺點:時間O(nlogn),總個數n和k差距大的時候,好比k=1,很不實用。數組
若是k<=logn,用部分排序算法更快(選擇排序和冒泡排序),時間O(n*k)。app
2.遞歸,把問題規模縮小。快排的思想是用一個數把數列分紅兩半,一半a小於該數,一半b大於該數,ui
若是b的個數b.size小於k,則在a中找k-b.size個最大數,spa
若是b的個數b.size大於k,則在b中找k個最大數。翻譯
【code】//用僞代碼翻譯過來的code,不算本身寫的= =code
void ipartition(vector<int> src, vector<int>& s1, vector<int>& s2) { int len=src.size(); int p=src[rand()%len];//wow! for(int i=0; i<src.size(); i++){ if(src[i]<p) s1.push_back(src[i]); else s2.push_back(src[i]); } //s1.size()<s2.size()?s1.push_back(p):s2.push_back(p); } vector<int> Kbig(vector<int> s, int k) { vector<int> ret; if(k<=0) return ret; if(s.size()<=k) return s; vector<int> s1; vector<int> s2; ipartition(s, s1, s2); if(s2.size()<k){ //copy(v1.begin(),v1.end(),back_inserter(v2)) vector<int> tmp=Kbig(s1, k-s2.size()); copy(tmp.begin(),tmp.end(),back_inserter(s2)); return s2; } else if(s2.size()>k){ return Kbig(s2, k); } else return s2; }
【注意】blog
1.ipartition的部分,產生一個隨機下標的方式:rand()%n,防止每次從s[0]開始劃分會產生退化。排序
2.原書有註釋的那一行,是將s[0]和是s[rand()%n]交換,而後從i=1開始計數,最後把劃分的界放在元素書較少的那一邊,
我以爲直接把用來劃分的界s[rand()%n]位置不變,等於該值時隨意放在哪邊。
3.vector沒有append方法,即將一個vector總體連在另外一個vector後面,這裏用copy(tmp.begin(),tmp.end(),back_inserter(s2));實現。
4.用數組和下標控制操做範圍的接口彷佛不太方便,故這裏選用vector類型,若是遇到用數組的要求再轉換。
5.時間複雜度是O(n*logk),和k的大小有關,不須要全排序。
【思路3】
用小根堆,前k個數造成一個小根堆做爲k個最大數的初始化,依次用第k+i個數和堆頂的數比較,若是比堆頂大,則堆頂設爲當前數,而且調整成小根堆,再與下一個數比較。
用小根堆的緣由是,要把第K+i個數與最大K個數的最小數比較,每次替換最小的數,時間是O(N*K).
【code】
void min_heapify(int src[], int i, int length) { int left=i*2+1; int right=i*2+2; int smallist=i; if(left<length&&src[left]<src[smallist]) smallist=left; if(right<length&&src[right]<src[smallist]) smallist=right; if(smallist!=i){ int temp=src[i]; src[i]=src[smallist]; src[smallist]=temp; min_heapify(src, smallist, length); } } void build_min_heap(int src[], int length) { for(int i=length/2; i>=0; i--) min_heapify(src, i, length); } void findKmax(int src[], int length, int k) { if(length<k){ cout<<"error"<<endl; return; } int i; int *heap=new int[k]; for(i=0; i<k; i++) heap[i]=src[i]; build_min_heap(heap, k); while(i<length){ if(src[i]>heap[0]){ heap[0]=src[i]; min_heapify(heap, 0, k); } } for(i=0; i<k; i++) cout<<heap[i]<<' '; delete heap []; }
【總結】
1.堆代碼分爲兩部分:調整堆、創建堆
2.堆的存儲結構是數組(向量也行吧),用下標規律表示父子關係。
(此代碼未經驗證)