堆的應用之 求前K最大值和求中值

2021-08-20 08:10:08 字數 2672 閱讀 7574

今天和大家一塊學習下面試中常見的兩個關於堆的面試題,第一:求k個最大值;第二:求中值元素。演算法和資料結構算是筆者的死穴了。

一、求前k個最大的值

首先能想到的是使用arrays.sort()進行排序後取前k個值即可,效率是o(n*log2^n)。

其次可以進行迴圈選擇k次,每次都從剩下的資料中選擇最大值,效率是o(n*k)。但若k值大於log2^(n),其效率還不如完全排序。

況且上述方法並沒有考慮到資料的動態性,當資料是動態新增的情況下,如何維護前k個值呢?

此時,維護乙個長度為k的陣列,陣列中的k個位置填充我們需要的前k個數值,面對源源不斷的資料,都先找到陣列中的最小值,將新來的資料和最小值進行比較,若是大於最小值,則將最小值替換成新數值。那麼問題來了,每來乙個數值都需找到陣列中的最小值進行k次比較,會不會略顯繁瑣呢?

上述方法也僅僅是青銅,真正的王者上場了。解決方法是用最小堆互為這k個數值。最小堆,顧名思義,根節點永遠是最小的數值,那麼新來的元素僅需和根節點進行比較即可:小於根節點則pass,否則新值取代根節點,並且向下調整堆,調整的效率為o(log2^k),這樣總體的效率是o(n*log2^k),是不是比上面的方法高效了很多了呢?

talk is cheap,so codes follow.

前方高能**

class topk

/*** 新增集合中的所有元素.

*/public

void

addall(collection<? extends e> c)

} public

void

add(e e)

comparable<? super e> heap = (comparable<? super e>) p.peek();

//新來的小於根節點,不做什麼東西

if (heap.compareto(e) > 0)

// 新來的大於根節點,把根節點拋棄,加入新來的數值

p.poll();

p.add(e);

} public

t toarray(t a)

/*** 返回第k大的值.

*/public e getkth()

}/**

* created by mollychin on 2018/5/28.

*/public

class

topktest );

top5.addall(integers);

system.out.println("保留5個最大的元素,輸出為:");

system.out.println(arrays.tostring(top5.toarray(new integer[0])));

system.out.println(top5.getkth());

}}

輸出結果為:

保留5個最大的元素,輸出為:

[87, 99, 88, 100, 554]

87

二、求中值

乙個簡單的思路是排序後取中間的那個值即可,效率是o(n*log2^n)。

但上述方法僅適用於全部數值已知,那麼面對動態新增的數值呢?

可以使用兩個堆,最大堆和最小堆。下面是思路:

假設中值是z,則最大堆維護的是小於等於z的數值,最小堆維護的是大於等於z的數值。但是呢,兩個堆都不包含m。

當有新的數值n到達的時候,n與z進行比較,按照步驟一的約定將n加入最大堆或者最小堆中。

走完第二步後,若最小堆和最大堆的元素個數相差2個或者2個以上,則將m加入元素較少的堆中,然後從元素較多的堆中的根節點移除並且賦值給z。

4.下面我們來看下**實現。

/**

* created by mollychin on 2018/5/28.

*/public

class

mediantest );

integermedian.addall(integers);

system.out.println("中位數是:"+integermedian.getm());

}}class median

private

intcompare(e e, e m)

public

void

add(e e)

if (compare(e, m) <= 0) else

if (minheap.size() - maxheap.size() >= 2) else

if (maxheap.size() - minheap.size() >= 2)

} public

void

addall(collection<? extends e> c)

} public e getm()

}

中位數是:45
總結

相比較排序,使用堆的效率可以大大提高,而且還可以應對資料源源不斷到來的情景,可以給出實時滿意的結果。這大概就是演算法和資料結構的藝術吧(逃

利用堆求最大或最小的前k個數

用堆在海量資料中找出最大或最小的k個數,效率非常高。1 在一組資料中找出最小的k個數 解題思路 要找出最小的k個數,我們可以先用這組資料中的k個數構建一棵 最大堆 然後再將剩下的元素與堆頂元素相比。如果大於堆頂元素,則不做處理,繼續向下比較。如果小於堆頂元素,則將堆頂元素與這個元素交換,然後再恢復堆...

動態求前n個最小值 最大值

注 由於最小值和最大值的分析過程完全相同,這裡我們只討論最小值的分析流程,最大值同理 每次給定乙個數值,詢問此數值以及之前給定數值中最小的n個數 例如給定數值的順序為 8 7 1 2 9 4,設n 3 乙個最直觀的方法是,每次新增新的資料後,將當前所有資料進行排序,選擇較小的n個 一次排序最快也要 ...

利用K 堆求最大的K個數

1.原理 1.1將資料存在陣列中,利用堆排排序陣列的前k個數 遞增 此時建立的是小堆,陣列的第乙個元素儲存堆中最小值。1.2從 k 1 個陣列元素遍歷到最後,每次都和堆頂元素對比,如果大於堆頂元素,交換兩者,調整堆。1.3輸出陣列前k個數,就是最大的k個數。include define k 3 vo...