如果不對斐波那契堆做任何decrease-key或delete操作,則堆中每棵樹就和二項樹一樣;但是如果執行這兩種操作,在一些狀態下必須要破壞二項樹的特徵,比如decrease-key或delete後,有的樹高為k,但是結點個數卻少於2^k。這種情況下,堆中的樹不是二項樹。
為什麼要進行級聯剪下,級聯剪下要幹什麼?
如果僅僅要切除父結點y的乙個結點x,則僅僅需要把結點x加入到根結點所在雙向鍊錶中,再檢測y是否mark==true即可,這是因為斐波那契中的樹並不一定是二項樹,近似二項樹也可以。當刪除y的第二個結點時,對在該路徑上所有mark域為true的非根結點,將其從所在的雙向鍊錶中刪除,並將其加入到f堆的最小樹的根節點組成的雙向鍊錶中,即只有在刪除同乙個結點偶數個孩子時,才要進行級聯剪枝,來維護二項樹性質,奇數個時(即乙個),對樹影響不大,莫管它,只標記一下即可。
為什麼偶數個的時候要遞迴往上刪除?
二項樹中在深度為i處恰有cki個結點(i=0, 1, 2, …, k)。試著如果不進行級聯剪枝,就可以發現,稍微刪得結點超過兩三個,最後的樹就會不成樣子,毫無章法。但是如果進行了級聯剪枝,在偶數個結點時進行級聯剪下時,原來是c30=1, c31=3, c32=3, c33=1, 減少兩個結點關鍵字後,變為:c20=1, c21=2, c22=1,二項式是對稱的,所以,偶數個結點時進行級聯剪枝可以保證類似上邊的正好使二項式減少乙個數量級。
#include
using namespace std;
//log(15)/log(1.618)=5.628
const
int d=5;
struct node
};struct fibheap
};fibheap makefibheap()
//insert、concatenate、remove都只處理左右關係(兄弟指標),
//不處理上下關係(父指標和孩子指標)。
//a和b都非空
void insert(node *a,node *b)
//將乙個新結點x插入h的根鍊錶
void fibheapinsert(fibheap &h,node *x)
else
++h.n;
}node *fibheapminimum(fibheap h)
//a和b都非空
void concatenate(node *a,node *b)
fibheap fibheapunion(fibheap &h1,fibheap &h2)
//a非空
void remove(node *a)
void fibheaplink(fibheap &h,node *y,node *x)
else insert(x->child,y);
y->p=x;
++x->degree;
y->mark=false;
}void consolidate(fibheap &h)
; node *sentinel=h.min->left;
bool flag=true;
for(node *w=h.min,*next;flag;w=next)
fibheaplink(h,y,x);
a[d++]=null;
}a[d]=x;
}h.min=null;
for(int i=0;i<=d;++i)
else}}
}node *fibheapextractmin(fibheap &h)
remove(z);
if(z==z->right)h.min=null;
else
--h.n;
}return z;
}//切斷
void cut(fibheap &h,node *x,node *y)
--y->degree;
insert(h.min,x);
x->p=null;
x->mark=false;
}//級聯切斷
void cascadingcut(fibheap &h,node *y)
}}//減小關鍵字的**流程基本就是:如果減小後的結點破壞了最小堆性質,則把它切下來(cut),
//即從所在雙向鍊錶中刪除,並將其插到由最小樹根節點形成的雙向鍊錶中,
//然後再從x->p到所在樹根節點遞迴執行級聯剪枝。
void fibheapdecreasekey(fibheap &h,node *x,int k)
if(x->keymin->key)h.min=x;
}//刪除乙個節點
void fibheapdelete(fibheap &h,node *x)
//執行fibheapinsert之後
// h.min
// |
// 21-17-24-18-52-38-30-26-46-39-41-35-3-7-23
////執行fibheapextractmin之後
// h.min
// |
// 26-35----------7
// | | |
// 39-30 41 17----18-23
// | | |
// 46 21 38-24
// |
// 52
////執行第一次fibheapdecreasekey之後
// h.min
// |
// 26-35-16-------7
// | | | |
// 39-30 41 52 17-18-23
// | | |
// 46 21 24
////執行第二次fibheapdecreasekey之後
// h.min
// |
// 26-35-16-15-18-7
// | | | |
// 39-30 41 52 17-23
// | |
// 46 21
int main()
; for(int i=0;i<15;++i)
fibheapextractmin(h);
//x指向38,y指向24
node *x=h.min->child->left->child->left,*y=x->right;
fibheapdecreasekey(h,x,16);
fibheapdecreasekey(h,y,15);
return
0;}
演算法導論筆記 19斐波那契堆
可合併堆是支援以下5 種操作的資料結構,其中每個元素都有乙個關鍵字 make heap 建立和返回乙個新的不含任何元素的堆。insert h,x 將乙個已填入關鍵字的元素x插入堆h中。minimum h 返回乙個指向堆h中具有最小關鍵字元素的指標。extract min h 從堆h中刪除最小關鍵字的...
演算法導論之斐波那契堆
斐波那契堆,和二項堆類似,也是由一組最小堆有序的樹構成。注意區別,不是二項樹,是有根而無序的樹。導論中,斐波那契堆只是具有理論上的意義,是以平攤分析為指導思想來設計的資料結構,主要是漸進時間界比二項堆有改善。斐波那契堆除去刪除元素操作外,其他操作只有o 1 的平攤執行時間,而二項堆需要o lgn 的...
斐波那契堆
以下是實現的程式 肯定可以再優化的。include include include include using namespace std class node delete m child m child null class fibonacciheap node insert int key v...