算法导论之斐波那契堆
斐波那契堆,和二項堆類似,也是由一組最小堆有序的樹構成。注意區別,不是二項樹,是有根而無序的樹。導論中,斐波那契堆只是具有理論上的意義,是以平攤分析為指導思想來設計的數據結構,主要是漸進時間界比二項堆有改善。斐波那契堆除去刪除元素操作外,其他操作只有O(1)的平攤運行時間,而二項堆需要O(lgn)的最壞情況運行時間。但若要斐波那契堆能轉化為實際應用,除要保證有相同平攤時間界限外,還需更簡單的數據結構。導論中提到斐波那契堆應用于最小生成樹和尋找單源最短路徑,可重點理解。
總結來說,斐波那契堆,相對二項堆來說,在多數操作上改善漸進時間,但僅適用于刪除操作動作較少的場景,且其結構復雜實用價值不大。下面看看斐波那契堆的結構及各操作的平攤分析勢能方法。
斐波那契堆的結點,包含指向父結點的指針p[x]、指向任一子女的指針child[x]、左兄弟指針left[x]、右兄弟指針right[x]、結點子女個數degree[x]、標記是否失去子女mark[x]。值得一提的是,通過左右兄弟指針,子女結點被鏈接成一個環形雙鏈表。
對給定的斐波那契堆H,通過指向包含最小關鍵字的樹根的指向min[H]來訪問,這個結點就是斐波那契堆中的最小結點。所有的樹根通過left和right指針構成一個環形雙鏈表,為堆的根表。指針min[H]指向根表中具有最小關鍵字的結點。H中所包含的結點個數為n[H]。斐波那契堆用勢能方法分析其操作的平攤性能,對給定的斐波那契堆H,t(H)表示H根表中樹的棵樹,m(H)表示H中有標記結點的個數,勢定義如下:
斐波那契堆的操作要分兩類,一類是建堆、插入結點、合并堆和抽取堆最小值;另一類是關鍵字值減少和結點刪除。
1)第一類操作斐波那契堆是一組無序的二項樹,符合二項樹的性質,性質四有所不同,描述為:無序二項樹Uk,根的度數是k,大于任何其他結點的度數;根的子女按照某種順序分別為U0,U1,…,Uk-1的根。n個結點的斐波那契堆由一組無序的二項樹構成。基本操作的平攤性能都是O(1),抽取最小值是O(lgn)。
2)第二類操作斐波那契堆是一組無序的樹,即不保持二項樹性質,操作的平攤性能是O(lgn)。
建堆、插入結點(直接作為一顆二項樹放在斐波那契堆的根表,然后將最小關鍵字指針重新調整)、尋找最小結點(第一個結點就是)、合并兩個斐波那契堆(簡單將兩個堆的根表合并即可),都是O(1)代價。重點要說明抽取最小結點的算法,和第二類中關鍵字值減小和刪除結點操作,都是O(lgn)代價。
1)抽取最小結點
抽取最小結點的處理邏輯很直接:將最小結點的子女都成為一個根,然后刪除最小結點,接著將度數相同的根鏈接起來,調整到每個度數只有一個根為止。具體算法如下:
Fun_Fib_Heap_Extract_Min(H){
??? z=min[H];
??? if z ≠ null
??????? then for each child x of z
??????????? do add x to root list of H
??????????? p[x]=null
??????? remove z from the root list of H?? //將最小結點的子女調整為根并刪除最小結點
??? if z=right[z] then min[H]=null
??? else min[H] = right[z]? //將右兄弟作為最小結點,就是堆的入口結點
???????? consolidate(H) //調整堆
??? n[H]=n[H]-1 //堆結點數減1
??? returun z
}
重點是堆調整,使根結點的度數都是唯一的,且保持無序二項樹性質。
Fun_ consolidate(H){
??? for i=0 to D(n[H]) //結點度數上界
??????? do A[i]=null
??? for each node w in the root list of H
??????? do x=w
?????????? d=degree[x]
?????????? while A[d] ≠ null
?????????????? do y=A[d]
?????????????? if key[x]<key[y] thenexchange(x,y)
?????????????? remove y form the root list of H
?????????????? make y a child of x,incrementingdegree[x]
?????????????? mark[y]=false
?????????????? A[d]=null
?????????????? d=d+1
?????????? A[d]=x //對根表中的每一個根w進行處理,使每個度數下至多只有一個根(發現有相同度數,小值作為根,大值下沉為子女),且數組A指向每一個留下的根。用A數組作為輔助數組,將根表中每個結點的度數映射過去。要對y進行標記,是勢函數計算依據。這種處理思路就使用利用結點度數0-n的最大值作為數組來存儲根表中結點的度數,是一種很有用的常量映射辦法。
??? min[H]=null
??? for i=0 to D(n[H])
??????? do if A[i] ≠ null
??????????? then add A[i] to the root list of H
??????????????? if min[H]=null orkey[A[i]]<key[min[H]]
??????????????? ????then min[H]=A[i]
}
2)關鍵字值減小
斐波那契堆結點關鍵字值減小,主要是保持最小堆有序的性質,具體算法如下:
Fun_Fib_Heap_DecreaseKey(H,x,k){//x結點關鍵值減少為k
??? if k>key[x] then return;
??? key[x]=k
??? y=p[x]
??? if y ≠ null and key[x] <key[y]
??????? then CUT(H,x,y)
???????????? Cascading-cut(H,y)
?? If key[x] <key[min[H]] then min[H]=x
}
如果x結點減小后的關鍵值小于父結點y,則要調整堆,具體算法如下:
Fun_CUT(H,x,y){
??? remove x from the child list ofy,decrementing degree[y]
??? add x to the root list of H
??? p[x] =null
??? mark[x]=false
}
將x鏈接到根表。
Fun_ Cascading-cut(H,y){
??? z=p[y]
??? if z ≠null
??????? then if mark[y]=false //失去一個子結點
??????????? then mark[y]=true
??????????? else CUT(H,y,z)
???????????????? Cascading-cut(H,z)
}
級聯處理,保持最小堆性質。刪除結點就可以通過減少結點關鍵值和抽取最小結點來完成,先把要刪除的結點關鍵值減少為負無窮大,然后抽取最小值結點來作為堆入口。
總結
以上是生活随笔為你收集整理的算法导论之斐波那契堆的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java键盘字符乱码判断代码
- 下一篇: Hive查询结果输出文件