1. 程式人生 > >大根堆 小根堆 找中位數

大根堆 小根堆 找中位數

集合中元素,前一半儲存在一個最大堆中,後一半儲存在一個最小堆中。

使用變數MaxHeapNum記錄最大堆元素的個數,使用變數MinHeapNum記錄最小堆元素的個數。控制MaxHeapNum與MinHeapNum的差不能超過1。每次將要插入的元素Num與最大堆頂部元素MaxHeapTop和最小堆的頂部元素MinHeapTop將進行比較,根據具體情況進行插入:


1.如果Num < MaxHeapTop,則
  1.1 如果MaxHeapNum <= MinHeapNum,將Num插入最大堆;
  1.2 如果MaxHeapNum == MinHeapNum + 1,將MaxHeapTop從最大堆中移到最小堆,並將Num插入最大堆。

2.如果MaxHeapTop <= Num <= MinHeapTop,則
  2.1 如果MaxHeapNum <= MinHeapNum,將Num插入最大堆;
  2.2 如果MaxHeapNum == MinHeapNum + 1,將Num插入最小堆;
3.如果Num > MinHeapTop,則
  3.1 如果MinHeapNum <= MaxHeapNum,將Num插入最小堆;
  3.2 如果MinHeapNum == MaxHeapNum + 1,將MinHeapTop移到最大堆中,將Num插入最小堆。

在每次插入後,都要根據情況對MaxHeapNum和MinHeapNum進行變更,並將有改動的堆進行堆調整。


上面的插入情況會保證最大堆和最小堆的元素個數差小於1,中位數就只在最大堆和最小堆的頂部元素中產生:如果最大堆和最小堆的元素個數相等,則中位數為最大堆和最小堆的頂部元素的平均值;否則,中位數為元素個數多的那個堆的堆頂元素。

複雜度分析:每次插入元素時的堆調整平均複雜度為O(log(N/2)),插入N次,所以總的複雜度為O(N*log(N/2))。

用一個最大堆存放比中位數小(或等於)的元素,用一個最小堆存放比中位數大(或等於)的元素。這裡關鍵的方法是insert(),每當要插入一個元素時,根據判斷條件將它插入最大堆或是最小堆,並更新最大堆和最小堆,使得最大堆和最小堆中元素的個數之差不超過1,這樣中位數就是最大堆或最小堆的堆頂元素。當最大堆和最小堆中元素個數不同(個數相差為1)時,元素個數多的那個堆的堆頂元素即為中位數;如果兩者元素個數相同,那麼中位數可以是最大堆和最小堆的堆頂元素的值取平均。下面的程式程式碼中,當兩者元素個數相同時,將最大堆的堆頂元素看做中位數。

插入(insert) (1)如果最大堆為空,將元素插入最大堆;(2)如果最小堆為空,將元素插入最小堆;(3)如果元素比最大堆的堆頂元素小且最大堆中元素個數不大於最小堆中元素個數,將元素插入最大堆;如果如果元素比最大堆的堆頂元素小但最大堆中元素個數大於最小堆中元素個數,那麼先把最大堆的堆頂元素插入最小堆,然後刪除最大堆的堆頂元素,最後把元素插入最大堆;(4)如果元素比最小堆的堆頂元素大且最小堆中元素個數不大於最大堆中元素個數,將元素插入最小堆;如果如果元素比最小堆的堆頂元素大但最小堆中元素個數大於最大堆中元素個數,那麼先把最小堆的堆頂元素插入最大堆,然後刪除最小堆的堆頂元素,最後把元素插入最小堆;(5)如果最大堆中元素個數小於最小堆中元素個數,將元素插入最大堆;否則將元素插入最大堆。