java 使用二叉堆實現 TopK 演算法

2021-08-01 16:59:46 字數 2578 閱讀 3905

首先 本小白是參考這裡寫鏈結內容 和這裡寫鏈結內容

兩位 博主的文章

1.首先,什麼是二叉堆,維基百科上是這麼描述的:

當父節點的鍵值總是大於或等於任何乙個子節點的鍵值時為最大堆。 當父節點的鍵值總是小於或等於任何乙個子節點的鍵值時為最小堆。

2.二叉堆一般用陣列來表示。如果根節點在陣列中的位置是1,第n個位置的子節點分別在2n和 2n+1。因此,第1個位置的子節點在2和3,第2個位置的子節點在4和5。以此類推。這種基於1的陣列儲存方式便於尋找父節點和子節點。

如果儲存陣列的下標基於0,那麼下標為i的節點的子節點是2i + 1與2i + 2;其父節點的下標是⌊(i − 1) ∕ 2⌋。

3.如果要向二叉堆中新添乙個數的話,如下圖:

**這裡寫鏈結內容

利用二叉堆演算法來實現 topn

實現流程是:

1、先讀取10個或100個數到陣列裡面,這就是我們的topn數.

2、呼叫生成小頂堆函式,把這個陣列生成乙個小頂堆結構,這個時候堆頂一定是最小的.

2.1、按照圖一的規則,把陣列的值按照二叉堆的索引位置放好。

2.2、從最後乙個有子節點的索引位置開始,如果其子節點的最小值比父節點的值小,那就交換子父節點的值;(其實就是把陣列的兩個值交換而已)

2.2.1、 如果其子節點還有子節點,就遞迴呼叫,把最小數往上頂。

2.3、再找倒數第二個有子節點的索引,再比較,再交換值。

3、從檔案或者陣列依次遍歷剩餘的所有數.

4、每遍歷出來乙個則跟堆頂的元素進行大小比較,如果小於堆頂元素則拋棄,如果大於堆頂元素則替換之.

5、跟堆頂元素替換完畢之後,在呼叫生成小頂堆函式繼續生成小頂堆,因為需要再找出來乙個最小的.

5.1、 其實,在選出的前10個數,猜想預設這個陣列存的就是最大的10個數,如果在剩餘的數裡面有比這10個數的最小數還大的,那就果斷放進來,把那個二叉堆的最小數丟擲,然後再找。。。

6、重複以上4~5步驟,這樣當全部遍歷完畢之後,我們這個小頂堆裡面的就是最大的topn,因為我們的小頂堆永遠都是排除最小的留下最大的,而且這個調整小頂堆速度也很快,只是相對調整下,只要保證根節點小於左右節點就可以.

7、演算法複雜度的話按top10最壞的情況下,就是每遍歷乙個數,如果跟堆頂進行替換,需要調整10次的情況,也要比排序速度快,而且也不是把所有的內容全部讀入記憶體,可以理解成就是一次線性遍歷.

理論講完了,下面就是**:

private listarraylist;

//生成小頂堆函式

void head(int arr, int idx)

if ((rightlength)&&arr[right]min = right;

}else

if (arr[idx]>arr[min])

}

@org.junit.test

public

void

testtopkmethod()

//打亂順序

collections.shuffle(arraylist);

int numarray = new

int[arraylist.size()];

for (int i = 0;iget(i);

}//先取出10個到陣列

listtoplist = arraylist.sublist(0,10);

system.out.println(toplist);

//獲取最後乙個有子節點的索引位置

//因為在構造小頂堆的時候是從最後乙個有左或右節點的位置

//開始從下往上不斷的進行移動構造(具體可看上面的圖去理解)

int idx = toplist.size()/2 - 1;

//生成小頂堆

int arr = new

int[toplist.size()];

for (int i =0;iget(i);

}for (int i = idx;i>=0;i--)

//這裡可以看到,就是開始遍歷剩下的所有元素

for (int i = arr.length;i//每遍歷乙個則跟堆頂元素進行比較大小

if (numarray[i]>arr[0])

}long endtime=system.currenttimemillis(); //獲取結束時間

感謝這裡寫鏈結內容

簡單方式博主,很受啟發。(我這耗時2.7s,php耗時1.4s,看起來我這**還是有些問題)

PHP 利用二叉堆實現TopK 演算法

在以往工作或者面試的時候常會碰到乙個問題,如何實現海量topn,就是在乙個非常大的結果集裡面快速找到最大的前10或前100個數,同時要保證記憶體和速度的效率,我們可能第乙個想法就是利用排序,然後擷取前10或前100,而排序對於量不是特別大的時候沒有任何問題,但只要量特別大是根本不可能完成這個任務的,...

使用C 實現二叉堆

二叉堆可以用來實現優先佇列。二叉堆是一棵完全二叉樹,除了葉子節點那一層,其他的層都是滿的,葉子節點那一層是從左往右依次存放的,因此它們的父子元素的索引有數學公式可以參考,對於節點i來說,它的左兒子是2i,右兒子是2i 1,它的父親節點是i 2向下取整,因此,在其內部我們可以通過陣列來實現元素的儲存,...

二叉堆實現二

堆可以視為一棵完全二叉樹,樹的每一層都是被填滿的,最後一層可能除外,所以堆可以用陣列來表示。對於陣列中任意位置 i上的元素,其左兒子在位置 i 2 1 其右兒子在位置 i 2 2 上,其父節點在位置 i 1 2 1處。二叉堆有兩種 最大堆和最小堆。最大堆中,除根結點外 其無父結點 每個結點的關鍵字都...