方法一: 使用partition函式,將陣列分為兩組。partition函式是快速排序中用來把陣列分成兩部分的函式。
(1)分為兩個組,sa和sb。
(2)若sa組的個數大於k,則繼續在sa分組中找取最大的k個數字 。
(3)若sa組中的數字小於k ,其個數為t,則繼續在sb中找取 k-t個數字 。
具體**實現:
[cpp]view plain
copy
print?
"font-size: 16px">#include
using
namespace std ;
const
int n = 8 ;
const
int k = 4 ;
int partition(int a ,int low , int high)
j++ ;
} //最後處理a[high]
swap(a[i+1] , a[high]) ;
return i + 1;
} int findk(int a , int low , int high , int k)
} int main()
; findk(a , 0 , n - 1 , k) ;
for(int i = 0 ; i < k ; i++)
cout<
system("pause") ;
return 0 ;
}
#include using namespace std ;
const int n = 8 ;
const int k = 4 ;
int partition(int a ,int low , int high)
j++ ;
}//最後處理a[high]
swap(a[i+1] , a[high]) ;
return i + 1;
} int findk(int a , int low , int high , int k)
}int main()
;findk(a , 0 , n - 1 , k) ;
for(int i = 0 ; i < k ; i++)
cout<
方法二 :
此種方法為常用方法,建立乙個大小為k的堆。每次遍歷陣列時,需要判斷是否需要加入堆中。
堆中儲存著的是最大的k個數字,但是若是需要插入堆中,則需要對堆進行調整時間為o(log k)。
全部的時間複雜度為o(n * log k)。
這種方法當資料量比較大的時候,比較方便。因為對所有的資料只會遍歷一次,第一種方法則會多次遍歷
陣列。 如果所查詢的k的數量比較大。可以考慮先求出k` ,然後再求出看k`+1 到 2 * k`之間的數字,然後
一次求取。
方法三:
利用二分的方法求取top k問題。
首先查詢 max 和 min,然後計算出 mid = (max + min) / 2
該演算法的實質是尋找最大的k個數中最小的乙個。
**如下:
[cpp]view plain
copy
print?
"font-size: 16px">#include
using
namespace std ;
const
int n = 8 ;
const
int k = 4 ;
/*利用二分的方法求取top k問題。
首先查詢 max 和 min,然後計算出 mid = (max + min) / 2
該演算法的實質是尋找最大的k個數中最小的乙個。
*/int find(int * a , int x) //查詢出大於或者等於x的元素個數
return sum ;
} int getk(int * a , int max , int min) //最終max min之間只會存在乙個或者多個相同的數字
cout<<"end"
} int main()
;
int x = getk(a , 554 , 2) ;
coutreturn 0 ;
}
#include using namespace std ;
const int n = 8 ;
const int k = 4 ;
/*利用二分的方法求取top k問題。
首先查詢 max 和 min,然後計算出 mid = (max + min) / 2
該演算法的實質是尋找最大的k個數中最小的乙個。
*/ int find(int * a , int x) //查詢出大於或者等於x的元素個數
return sum ; }
int getk(int * a , int max , int min) //最終max min之間只會存在乙個或者多個相同的數字
cout<<"end"<
方法4:
如果n個數都是正數,取值範圍不太大,可以考慮用空間換時間。申請乙個包括n中最大值的maxn大小的陣列count[maxn],count[i]表示整數i在所有整數中的個數。這樣只要掃瞄一遍陣列,就可以得到低k大的元素。
[cpp]view plain
copy
print?
for(sumcount = 0, v = maxn -1; v >=0; v--)
return v;
for(sumcount = 0, v = maxn -1; v >=0; v--)
return v;
擴充套件:
1. 如果需要找出n個數中最大的k個不同的浮點數呢?比如,含有10個浮點數的陣列(1.5,1.5,2.5,3.5,3.5,5,0,- 1.5,3.5)中最大的3個不同的浮點數是(5,3.5,2.5)。
個人覺得除了最後一種方法不行,其他的都可以。因為最後一種需要是正數。
2. 如果是找第k到第m(0
個人覺得可以用小根堆來先求出m個最大的,然後從中輸出k到m個。
網上答案:可以採用小頂堆來實現,使用對映二分堆,可以使更新的操作達到o(logn)。
4. 在實際應用中,還有乙個「精確度」的問題。我們可能並不需要返回嚴格意義上的最大的k個元素,在邊界位置允許出現一些誤差。當使用者輸入乙個query的時候,對於每乙個文件d來說,它跟這個query之間都有乙個相關性衡量權重f (query, d)。搜尋引擎需要返回給使用者的就是相關性權重最大的k個網頁。如果每頁10個網頁,使用者不會關心第1000頁開外搜尋結果的「精確度」,稍有誤差是可以接受的。比如我們可以返回相關性第10 001大的網頁,而不是第9999大的。在這種情況下,演算法該如何改進才能更快更有效率呢?網頁的數目可能大到一台機器無法容納得下,這時怎麼辦呢?
網上答案:答:
正如提示中所說,可以讓每台機器返回最相關的
k'個文件,然後利用歸併排序的思想,得到所有文件中最相關的
k個。 最好的情況是這
k個文件在所有機器中平均分布,這時每台機器只要
k' = k / n (n
為所有機器總數);最壞情況,所有最相關的
k個文件只出現在其中的某一台機器上,這時
k'需近似等於
k了。我覺得比較好的做法可以在每台機器上維護乙個堆,然後對堆頂元素實行歸併排序。
5. 如第4點所說,對於每個文件d,相對於不同的關鍵字q1, q2, …, qm,分別有相關性權重f(d, q1),f(d, q2), …, f(d, qm)。如果使用者輸入關鍵字qi之後,我們已經獲得了最相關的k個文件,而已知關鍵字**跟關鍵字qi相似,文件跟這兩個關鍵字的權重大小比較靠近,那麼關鍵字qi的最相關的k個文件,對尋找**最相關的k個文件有沒有幫助呢?
解答:肯定是有幫助的。 qi最相關的k個文件可能就是**的最相關的k個文件,可以先假設這k個就是,然後根據問題四的解法獲得k',分別和這k個比較,可以用堆進行比較,從而獲得**最相關的k個文件。由於最開始的k個文件極有可能是最終的k個文件,所以k'和k比較的次數可能並不多。
參考:
本文出自:
程式設計之美 尋找最大的K個數
有很多個無序數,我們姑且假定他們各不相等,怎麼挑選出其中最大的若干個數呢?如果這個資料量很大,比如1億個,如果所存資料是浮點型呢?我們該怎麼處理呢?分兩部分,第一部分是我個人的解答,第二部分是書上的解答 第一部分 1,如果這個問題裡的資料都是整數,這個問題利用hash對映應該很簡單,就是在開闢乙個陣...
程式設計之美 尋找最大的K個數
有很多個無序數,我們姑且假定他們各不相等,怎麼挑選出其中最大的若干個數呢?如果這個資料量很大,比如1億個,如果所存資料是浮點型呢?我們該怎麼處理呢?分兩部分,第一部分是我個人的解答,第二部分是書上的解答 第一部分 1,如果這個問題裡的資料都是整數,這個問題利用hash對映應該很簡單,就是在開闢乙個陣...
程式設計之美 尋找最大的k個數
有很多無序的數,我們姑且假定它們各不相等,怎麼選出其中最大的若干個數呢?idea 1 先用快速排序或者堆排序進行排序,然後取出最大的k個數,時間複雜度為o nlogn o k o nlogn idea 2 進行k趟最大冒泡或者k次大頂堆的輸出,時間複雜度為o n k 根據k與logn的大小比較,選取...