結構之美——優先隊列三大結構(一)——二項堆

來源:互聯網
上載者:User

這三篇文章主要講解二項堆、斐波那契堆、Pairing 堆,這三種結構主要用於優先隊列的實現。資料主要參考《演算法導論》和或互連網。

 

《演算法導論》第19章講到了二項堆

 

1.二項堆簡介                                                                                

 

二項堆是二項堆是由一組二項樹組成,在給出二項堆的定義之前,首先我們來定義什麼是二項樹。

1.1二項樹

二項樹是一種遞迴的有序樹。定義如下:

1. 二項樹B[0]僅僅包含一個節點

2. B[k]是由兩棵B[k-1]二項樹組成,其中一顆樹是另外一顆樹的左孩子。

下面(a)是二項樹B[k]遞迴定義,(b)二項樹B[0]到B[4],(c)看待二項樹的另一種方式:

 二項樹的性質:

1. 對於樹B[k]該樹含有2^k個節點;

2. 樹的高度是k;

3. 在深度為i中含有Cik節點,其中i = 0, 1,2 ... , k;

4. 根的度數為k,最大,

推論:n節點的二項樹,任意節點的最大度數為log(n)

1.2二項堆

二項堆是由一組滿足下面的二項樹組成:

1.  H中的每個二項樹遵循最小堆性質(類似小頂堆);

2. 對於任意的整數k的話,在H只存在一個度數是k的二項樹;

另外定義:

1. 二項堆的度數定義成子女個數;

2. 定義二項堆的根表是二項樹的根節點形成的鏈表;

 

2.資料結構                                                                           

 

瞭解了什麼二項堆的定義和使用情境之後,我們來看看如何儲存二項堆?

首先定義二項堆中每個節點的類型:

1. parent:指向父節點

2. sibling:指向右邊的兄弟節點

3. child:定義該節點的子節點

4. degree:定義該節點的度數

5. 其他應用情境中需要的資料

struct heap_node{struct heap_node*parent;struct heap_node*next;struct heap_node*child;unsigned intdegree;void*value;struct heap_node**ref;}; 

對於定義的欄位,對於根表中的節點和非根表中的元素是不相同的,根表中的節點的parent全部是空,sibling指向的是根表中的下一個元素;對於非根表中的節點的話,parent指向的是該節點的父節點,sibling指向該節點的兄弟節點。

定義二項堆資料類型:

1. 根表的前端節點

2. 其他應用需要的資料 

struct heap {struct heap_node*head;struct heap_node*min;}; 

 

3.二項堆操作                                                                              

 

3.1建立一個新的二項堆

MAKE-BINOMIAL-HEAP,

分配並返回一個對象H,head[H]=NIL;running time is(1).

僅僅將根表的前端節點指向null:

static inline void heap_init(struct heap* heap){heap->head = NULL;heap->min  = NULL;// 其他動作

3.2尋找最小關鍵字

BINOMIAL-HEAP-MINIMUM,

返回一個指標,指向最小關鍵字節點。

由於二項堆中每個二項樹都是遵循最小堆性質的,所以最小元素一定是在根表中,遍曆根表一次即可找出最小元素:

BINOMIAL-HEAP-MINIMUM(H)

1  y  NIL

2  x head[H]

3  min 

4  while x  NIL

5      do if key[x] < min

6            then min key[x]

7                 y x

8         x sibling[x]

9  return y

3.3 合併作業(MOST)

BINOMIAL-HEAP-UNION

二項堆的合併作業是一個比較複雜,但是至關重要的一個過程,這裡假設需要合并的兩個二項堆是H1和H2,如果簡單的將H1和H2的根表(兩個鏈表)進行合并的話,顯然這可能是違反了二項堆定義的第二條:

 2. B[k]是由兩棵B[k-1]二項樹組成,其中一顆樹是另外一顆樹的子樹。

 這就是二項堆合併作業的主要需要解決的問題:兩個二項堆合并完成之後,可能在根表中存在兩個度數相同的節點,需要將度數相同的節點合并成一個新的節點。

這裡我們進一步將這個問題現在轉換成了:已知H1根表和H2的根表中每個節點的度數,並且H1和H2的根表已經是按照度數排序的,如何H1和H2根表合并,並且新的根表中不存在兩個度數相同的節點。

一個樸素的思想就是現將H1和H2合并,然後在進行適當的調整,將兩個度數相同的節點合并掉,這樣保證了新的根表中不存你在兩個度數相同的節點。那麼基本的程式架構:

union(H1, H2)
{
#1:合并H1和H2的根表,產生新的根表H,並且H的節點是按照度數排序的;
#2:將H中度數相同的兩個節點合并,直到根表H中不存在兩個度數相同的節點;

繼續細化上面的思路,#1是比較簡單的,類似于歸並排序中的合并的思路,但是對於#2而言,由於H是排序完成的,那麼我們僅僅需要將H遍曆一遍,如果存在兩個相同的度數,合并即可。

 

case1: 當前節點的degree[x]與其後繼結點的degree[next-x]不相等;後移;

case2: 當前節點的degree[x]與其後繼的後繼degree[sibling[next-x]]相等;後移;(三個深度都一樣)

else:

 degree[x] = degree[next-x]:

  case3: if(key[x] <= key[next-x]) : sibling[x] = sibling[next-x], BINOMIAL-LINK(next-x,x)//next-x賦給x的左孩子

  case4: if(key[x] > key[next-x]) : sibling[prev-x] = next-x, BINOMIAL-LINK(x,next-x)//x賦給next-x的左孩子

 

3.4 插入一個節點

 BINOMIAL-HEAP-INSERT(H,x)

首先構建一個只包含一個元素的二項堆H',O(1),再合并,O(log(n));

1  H'  MAKE-BINOMIAL-HEAP()

2  p[x]  NIL

3  child[x]  NIL

4  sibling[x]  NIL

5  degree[x]  0

6  head[H']  x

7  H  BINOMIAL-HEAP-UNION(H,H')

3.5 抽取最小元素

BINOMIAL-HEAP-EXTRACT-MIN

1  find the root x with the minimum key in the root list of H, MAKE-BINOMIAL-HEAP

and remove x from the root list of H

2  H'  MAKE-BINOMIAL-HEAP()

3  reverse the order of the linked list of x's children,

and set head[H'] to point to the head of the resulting list 逆向串連x的孩子到head[H']

4  H  BINOMIAL-HEAP-UNION(H,H')合并

5  return x

 

 

 

3.6 減小一個關鍵字的值

 BINOMIAL-HEAP-DECREASE-KEY (H,x,k)

將y減小到7,冒泡上升即可。

3.7 刪除一個關鍵字

 BINOMIAL-HEAP-DELETE(H,x)

將刪除元素當做無窮小,利用 BINOMIAL-HEAP-DECREASE-KEY (H,x,k)冒泡上升到樹根,再刪除BINOMIAL-HEAP-EXTRACT-MIN(H)

 

1 BINOMIAL-HEAP-DECREASE-KEY(H,x,-)

2 BINOMIAL-HEAP-EXTRACT-MIN(H)

 

4.應用情況

我們在什麼情況下使用“二項堆”?

如果是不支援所謂的合併作業union的話,普通的堆的資料結構就是一種很理想的資料結構。 但是如果想要支援集合上的合併作業的話,最好是使用二項堆或者是斐波那契堆,普通的堆在union操作上最差的情況是O(n),但是二項堆和斐波那契堆是O(lgn)。

                                  Binary heap              Binomial heap()        Fibonacci heap

                            二元堆積(最壞情況)     二項堆(最壞情況) (斐波那契堆(平攤))

Procedure    (worst-case)    (worst-case)       (amortized)

--------------------------------------------------------------

MAKE-HEAP         (1)            (1)            (1)

INSERT           (lg n)        O(lg n)           (1)

MINIMUM          (1)          O(lg n)           (l)

EXTRACT-MIN      (lg n)        (1g n)         O(lg n)

UNION             (n)          O(lg n)           (1)

DECREASE-KEY     (lg n)        (lg n)           (1)

DELETE            (1g n)        (lg n)         O(lg n)

 

5.參考資料

演算法導論:http://net.pku.edu.cn/~course/cs101/2007/resource/Intro2Algorithm/book6/chap20.htm

部落格園(內含代碼):http://www.cnblogs.com/xuqiang/archive/2011/06/01/2065549.html

 ITEYE(完整代碼):http://dsqiu.iteye.com/blog/1714961

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.