Java最小堆解決TopK問題

2021-06-13 03:51:07 字數 1760 閱讀 3844

topk問題是指從大量資料(源資料)中獲取最大(或最小)的k個資料。

對於這個問題,解決方法有很多:

方法一:對源資料中所有資料進行排序,取出前k個資料,就是topk。

但是當資料量很大時,只需要k個最大的數,整體排序很耗時,效率不高。

方法二:維護乙個k長度的陣列a,先讀取源資料中的前k個放入陣列,對該陣列進行公升序排序,再依次讀取源資料第k個以後的資料,和陣列中最小的元素(a[0])比較,如果小於a[0]直接pass,大於的話,就丟棄最小的元素a[0],利用二分法找到其位置,然後該位置前的陣列元素整體向前移位,直到源資料讀取結束。

這比方法一效率會有很大的提高,但是當k的值較大的時候,長度為k的資料整體移位,也是非常耗時的。

對於這種問題,效率比較高的解決方法是使用最小堆

最小堆(小根堆)是一種資料結構,它首先是一顆完全二叉樹,並且,它所有父節點的值小於或等於兩個子節點的值

最小堆的儲存結構(物理結構)實際上是乙個陣列。如下圖:

堆有幾個重要操作:

buildheap:將普通陣列轉換成堆,轉換完成後,陣列就符合堆的特性:所有父節點的值小於或等於兩個子節點的值。

heapify(int i):當元素i的左右子樹都是小根堆時,通過heapify讓i元素下降到適當的位置,以符合堆的性質。

回到上面的取topk問題上,用最小堆的解決方法就是:先去源資料中的k個元素放到乙個長度為k的陣列中去,再把陣列轉換成最小堆。再依次取源資料中的k個之後的資料和堆的根節點(陣列的第乙個元素)比較,根據最小堆的性質,根節點一定是堆中最小的元素,如果小於它,則直接pass,大於的話,就替換掉跟元素,並對根元素進行heapify,直到源資料遍歷結束。

最小堆的實現:

public class minheap

// 將陣列轉換成最小堆

private void buildheap()

}private void heapify(int i)

// 獲取右結點的陣列下標

private int right(int i)

// 獲取左結點的陣列下標

private int left(int i)

// 交換元素位置

private void swap(int i, int j)

// 獲取對中的最小的元素,根元素

public int getroot()

// 替換根元素,並重新heapify

public void setroot(int root)

}

利用最小堆獲取topk:

public class topk;		

// 獲取top5

int top5 = topk(data, 5);

for(int i=0;i<5;i++)

}// 從data陣列中獲取最大的k個數

private static int topk(int data,int k)

// 轉換成最小堆

minheap heap = new minheap(topk);

// 從k開始,遍歷data

for(int i= k;iroot)

}return topk;

}}

最大堆 最小堆Java實現,解決TOP K問題

最大堆,最小堆類似,以下以最小堆為例進行講解。最小堆是滿足以下條件的資料結構 它是一棵完全二叉樹 所有父節點的值小於或等於兩個子節點的值 除了最後一層之外的其他每一層都被完全填充,並且所有結點都保持向左對齊。對於topk問題,解決方法有很多 方法一 對源資料中所有資料進行排序,取出前k個資料,就是t...

最大堆 最小堆 解決TOPK問題

堆 實質是一顆完全二叉樹,最大堆的特點 父節點值均大於子節點 最小堆的父節點值均小於子節點 一般使用連續記憶體儲存堆內的值,因而可以根據當前節點的索引值推斷子節點的索引值 節點i的父節點為 i 1 2 節點j的左子結點 j 2 1 節點j的右子結點 j 2 2 以下 實現了最大堆最小堆,當比較函式使...

java解決topk問題

面試題中經常用到堆,這裡總結一下。方法一 對源資料中所有資料進行排序,取出前k個資料,就是topk。但是當資料量很大時,只需要k個最大的數,整體排序很耗時,效率不高。方法二 維護乙個k長度的陣列a,先讀取源資料中的前k個放入陣列,對該陣列進行公升序排序,再依次讀取源資料第k個以後的資料,和陣列中最小...