演算法導論之斐波那契堆

2021-07-16 05:14:37 字數 2971 閱讀 6165

斐波那契堆,和二項堆類似,也是由一組最小堆有序的樹構成。注意區別,不是二項樹,是有根而無序的樹。導論中,斐波那契堆只是具有理論上的意義,是以平攤分析為指導思想來設計的資料結構,主要是漸進時間界比二項堆有改善。斐波那契堆除去刪除元素操作外,其他操作只有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]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]]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] then cut(h,x,y)

cascading-cut(h,y)

if key[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)

級聯處理,保持最小堆性質。刪除結點就可以通過減少結點關鍵值和抽取最小結點來完成,先把要刪除的結點關鍵值減少為負無窮大,然後抽取最小值結點來作為堆入口。

演算法導論19(斐波那契堆)

如果不對斐波那契堆做任何decrease key或delete操作,則堆中每棵樹就和二項樹一樣 但是如果執行這兩種操作,在一些狀態下必須要破壞二項樹的特徵,比如decrease key或delete後,有的樹高為k,但是結點個數卻少於2 k。這種情況下,堆中的樹不是二項樹。為什麼要進行級聯剪下,級聯...

演算法導論筆記 19斐波那契堆

可合併堆是支援以下5 種操作的資料結構,其中每個元素都有乙個關鍵字 make heap 建立和返回乙個新的不含任何元素的堆。insert h,x 將乙個已填入關鍵字的元素x插入堆h中。minimum h 返回乙個指向堆h中具有最小關鍵字元素的指標。extract min h 從堆h中刪除最小關鍵字的...

斐波那契堆

以下是實現的程式 肯定可以再優化的。include include include include using namespace std class node delete m child m child null class fibonacciheap node insert int key v...