算法导论之二项堆
每件事物都有其應需而生的目的,既然存在了,一定有其出現的因和果。二項堆的存在,就是因為二叉堆在Union操作上性能不如意而被發明的。二項堆的Union操作只需O(lgn)時間就可以完成兩個二項堆的合并(總共n個元素)。
二叉堆是完全二元樹(二叉樹)或者是近似完全二元樹(二叉樹)。二叉堆有兩種:最大堆和最小堆。最大堆:父結點的鍵值總是大于或等于任何一個子節點的鍵值;最小堆:父結點的鍵值總是小于或等于任何一個子節點的鍵值。
那么二項堆的定義呢?二項堆是由一組二項樹組成,所以先看二項樹定義。
二項樹Bk是一種遞歸定義的有序樹。二項樹B0只包含一個節點。二項樹Bk由兩顆樹Bk-1連接而成:其中一顆樹的根式另一個樹的根的最左孩子。二項樹Bk具有以下性質:
1)共有2k個節點
2)樹的高度為k
3)在深度i處恰有個節點,其中i=0,1,…,k
4)根的度數為k,大于任何其他結點的度數,并且如果根的子女從左到右編號為k-1,k-2,…,1,0,子女i是子樹的Bi根。
二項堆H是由一組二項樹組成,并滿足以下性質:
1)H中的每個二項樹都遵循最小堆性質:結點的關鍵字大于或等于其父節點的關鍵字;
2)對任意非負整數k,在H中至多有一棵二項樹的根具有度數k。
這兩點總結來說,關系到二項堆中二項樹的兩點,一是結點度數,另一個是節點關鍵字值。首先關鍵字值要有序,父結點要小于子結點,其次,二項堆中二項樹的根結點度數要互異(不能有兩棵二項樹的根的度數是一樣)。這是在二項堆操作中一定要守恒的。二項堆中結點的域有:指向父節點的指針p[x]、指向最左孩子的指針child[x]、指向緊右兄弟的指針sibling[x]、結點度數degree[x]、關鍵字值key[x]。
二項堆操作,如創建、查找最小關鍵字、刪除關鍵字等都要維持其性質,其中合并兩個二項堆需要重點說明其算法和性能。
Fun_Binominal_heap_Union(H1,H2){
??? Make_Binominal_Heap(H);//建一個新堆
??? head[H]=Binominal_Heap_Merge(H1,H2);//合并成一個按度數遞增次序排列的鏈表,堆的根按照度數遞增作為新堆的根
??? if head[H]=null then return H;
??? prev[x]=null;
??? x=head[H];
??? next[x]=sibling[x];//第一棵樹根作為第一個結點
??? while next[x] is not null
??????? do if (degree[x] ≠degree[next[x]]
or(sibling[next[x]] is not null and degree[x]=dgree[sibling[next[x]]]
thenprev[x]=x?
???? x=next[x]
??????????? else if key[x] =< key[next[x]]
???????????????? thensibling[x]=sibling[next[x]]
????????????????????? Binoial_link(next[x],x);
??????????? else if prev[x]=null
??????????????? then head[H]=next[x]
??????????????? else sibling[prev[x]]=next[x]
??????????????? ?????Binoial_link(x,next[x]);
???????????????????? x=next[x];
??????????? next[x]=sibling[x];
??????? return H;
}
函數內,主要是對合并后結點做處理,以確保滿足二項堆和二項樹性質,可以看到主要對結點的比較就是度數和關鍵字值??聪聝蓚€度數相同的二項樹Bk-1合并成一顆樹Bk的函數。
Fun_ Binoial_link(x,y){
??? p[y]=x; //x作為y的父結點
??? sibling[y]=child[x];//x的孩子成為y的兄弟
??? child[x]=y;
??? degree[x]=degree[x]+1;
}
Binominal_heap_Union函數運行時間是O(lgn),其中n是二項堆H1(n1)和H2(n2)中總的結點數。H1至多包含lgn1+1個根,H2至多包含lgn2+1個根,合并后H至多包含2lgn+2,即O(lgn)個根。而執行函數的時間主要是在根結點循環,所以總共至多執行lgn2+2次迭代。
比較有趣的一個操作是當關鍵字值減少時調整二項堆使其保持性質,也是需要O(lgn)運行時間,要去判斷關鍵字值。那么能否先刪除關鍵字再作為新的關鍵字插入呢?新關鍵字插入導論中沒有給出,但我想可以作為堆合并來處理,因為一個結點就是一顆二項樹或二項堆,所以時間也是O(lgn),但刪除關鍵字的時間也需要O(lgn),總共需要O(2lgn)次,所以還是直接在原來結點調整值,然后保持二項堆性質。
雖然理解了定義和基本操作,但二項堆還沒想到具體應用點。總結
- 上一篇: shell一段脚本的一点经验(实时文件流
- 下一篇: Centos下Web中间件Jboss应用