取一個集合的前n個最大或最小值

 

《編程珠璣》第十四章的一個問題是:

在具有10億個數值的文件中找出最大的100萬個數組。

 

使用堆解決這個問題的思路

1. 取10億個數值中的最初的100萬個,放到一個堆中,初始化這個堆爲小頂堆。

2. 依次取剩下的每個數值,用取出的這個值和小頂堆的最小值比較:

   如果大於最小值,用這個值替換小頂堆的最小值,調整堆使得它還是小頂堆。

   如果小於或者等於最小值,則繼續取下一個值。

最後這個堆包含的就是100萬個最大值。

 

這個問題簡單推廣就是:尋找一個無序集合中前n個最大或者最小的值。也等價於:尋找一個無序集合中理解。這個思路好理解。嘗試嚴格證明這個思路。

M是一個集合,要取其中的前n個最大值。

假設A是初始的n個元素組成的堆,則剩下的元素組成集合X=M-A。假想存在一個集合B,它存放X中的元素和A中最小值比較後的較小的值。對一個元素x(i)(屬於X, i表示第i個元素),它和A的最小值比較,如果x(i)大,則把x(i)放入A,把A的最小值放入假想的集合B中(實際沒有放入,假想),記此時的A爲A(i),B爲B(i)。假設X中元素有N個,則A,B對應的變化是:

A(0),A(1),…,A(N-1),A(N)

B(0),B(1),…,B(N-1),B(N)

A(N)的元素就是前n個最大的值。

我們需要證明的就是任意一個屬於B(N)的元素,一定不大於A(N)中的任意一個元素,或者說一定不大於A(N)中的最小值。

證明:

假設元素b屬於B(N),則b來自於A中,或者來至於X中。

如果b來至於A中,則b一定是某次A的最小值,然後被X中的一個比它大的值替換。則一定存在A(j-1)(0<=j<=N-1),滿足b=Min(A(j-1)),同時b<Min(A(j))。我們知道每次A變化時,一定是一個較大的值替換了最小的值,所以Min(A(0))<=Min(A(1))<=…<=Min(A(N))。所以b<Min(A(j))<=Min(A(N))。

如果b來至於X中,則一定是從X中取出b和對應A(j)比較時,b<=Min(A(j))。所以b<=Min(A(j))<=Min(A(N))。

所以B(N)中的任意一個元素不大於A(N)的最小元素。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章