斐波那切堆資料結構有兩種用途。第一種,它支援一系列操作,這些操作構成了所謂的「可合併堆」;第二種,斐波那切堆的一些操作可以在常數攤還時間內完成,這使得這種資料結構非常適合於需要頻繁呼叫這些操作的應用。
可合併堆是支援以下5種操作的一種資料結構,其中每個元素都有乙個關鍵字:
- make_heap():建立和返回乙個新的不含任何元素的堆。
- insert(h, x):將乙個已填入關鍵字的元素x插入堆h中。
- minimum(h):返回乙個指向堆h中具有最小關鍵字元素的指標。
- extract_min(h):從堆h中刪除最小關鍵字的元素,並返回乙個指向該元素的指標。
- union(h1, h2):建立並返回乙個包含堆h1和堆h2中所有元素的新堆。堆h1和堆h2由這一操作「銷毀」。
除了以上可合併的操作外,斐波那契堆還支援以下兩種操作:
- decrease_key(h, x, k):將堆h中元素x的關鍵字賦予新值k,假定新值k不大於當前的關鍵字。
- delete(h, x):從堆h中刪除元素x。
乙個斐波那切堆是一系列具有最小堆序的有根樹的集合。每棵樹均遵循最小堆性質:每個結點的關鍵字大於或等於它的父結點的關鍵字。
每個結點x包含乙個指向它父結點的指標x.p和乙個指向它的某乙個孩子的指標x.child。x的所有孩子被鏈結成乙個環形的雙向鍊錶,稱為x的孩子鍊錶。孩子鍊錶中的每個孩子y具有指標y.left和y.right,分別指向y的左兄弟和右兄弟。如果y是僅有的乙個孩子,則y.left=y.right。
每個結點有另外兩個屬性。把結點x的孩子鍊錶中的孩子數目儲存在x.degree,在乙個n個結點的斐波那切堆中任何結點的最大度數都有上界d(n),並且d(n) ≤ o(lgn)。布林值屬性x.mark指示結點x自從上一次成為另乙個結點的孩子後,是否失去過孩子。新產生的結點是未標記過的,並且當結點x成為另乙個結點的孩子時,它便成為未被標記結點。
通過指標h.min來訪問乙個給定的斐波那切堆h,該指標指向具有最小關鍵字的樹的根結點,把這個結點稱為斐波那切堆的最小結點。如果不止乙個根結點具有最小關鍵字,那麼這些根結點的任何乙個都有可能成為最小結點。如果乙個斐波那切堆h是控的,那麼h.min為nil。
在斐波那切堆中,所有樹的根都用其left和right指標鏈成乙個環形的雙鏈表,該雙鏈表稱為斐波那切堆的根鍊錶。指標h.min指向根煉表中關鍵字最小的那個結點。
斐波那切堆h中還有另乙個屬性:h.n,表示h中當前的結點數目。
建立乙個新的斐波那切堆,make_fib_heap過程分配並返回乙個斐波那切堆物件h,其中h.n=0和h.min=nil,h中不存在樹。
將結點x插入斐波那切堆h中,假定該結點已經被分配,x.key已經被賦值。
fib_heap_insert(h, x)
x.degree = 0
x.p = nil
x.child = nil
x.mark = false
if h.min == nil
create
a root list for h containing just x
h.min = x
else
insert x into h』s root list
if x.key < h.min.key
h.min = x
h.n = h.n + 1
斐波那切堆的最小結點可以通過指標h.min得到。
下面的過程合併斐波那契堆h1和h2,並在該過程中銷毀h1和h2。它簡單的將h1和h2的根鍊錶鏈結,然後確定新的最小結點,之後,表示h1和h2的物件將不再使用。
fib_heap_union(h1, h2)
h = make_fib_heap()
h.min = h1.min
concatenate the root list of h2 with
the root list of h
if (h1.min == nil) or (h2.min ≠ nil and h2.min.key < h1.min.key)
h.min = h2.min
h.n = h1.n + h2.n
return h
假定當乙個結點從鍊錶中移除後,留在鍊錶中的指標要被更新,但是抽取出的結點中的指標並不改變。該**還呼叫乙個輔助過程consolidate。
fib_heap_extract_min(h)
z = h.min
if z ≠ nil
foreach child x of z
add x to
the root list of h
x.p = nil
remove z from
the root list of h
if z == z.right
h.min = nil
else
h.min = z.right
consolidate(h)
h.n = h.n – 1
return z
fib_heap_extract_min首先將最小結點的每個孩子變為根結點,並從根煉表中刪除該最小結點。然後通過把具體相同度數的根結點合併的方法來鏈結成根鍊錶,直到每個度數至多只有乙個根在根煉表中。
下一步是合併h的根鍊錶,通過呼叫consolidate(h)來減少斐波那切堆中樹的數目。合併根鍊錶的過程為重複執行以下步驟,直到根煉表中的每乙個根有不同的度數。
1. 在根煉表中找到兩個具有相同度數的根x和y。不失一般性,假定x.key≤y.key。
2. 把y鏈結到x:從根煉表中移除y,呼叫fib_heap_link過程,使y成為x的孩子。該過程將x.degree屬性增1,並清除y上的標記。
過程consolidate使用乙個輔助陣列a[0..d(h.n)]來記錄根結點對應的度數的軌跡。如果a[i]=y,那麼當前的y是乙個具有y.degree=i的根。
consolidate(h)
let a[0..d(h.n)]be a
new array
for i = 0
to d(h.n)
a[i] = nil
foreach node w in
the root list of h
x = w
d = x.degree
while a[d] ≠ nil
y = a[d]
if x.key > y.key
exchange x with y
fib_heap_link(h, y, x)
a[d] = nil
d = d + 1
a[d] = x
h.min = nil
for i = 0
to d(h.n)
if a[i] ≠ nil
if h.min == nil
create
a root list for h containing just a[i]
h.min = a[i]
else
insert a[i] into h』s root list
if a[i].key < h.min.key
h.min = a[i]
fib_heap_link(h, y, x)
remove y from
the list of h
make y a child of x, incrementing x.degree
y.mark = false
假定從乙個鍊錶中移除乙個結點不改變移除的結點的任何結構屬性。
fib_heap_decrease_key(h, x, k)
if k > x.key
error 「new
keyis greater then current key」
x.key = k
y = x.p
if y ≠ nil and x.key
< y.key
cut(h, x, y)
cascading_cut(h, y)
if x.key
< h.min.key
h.min = x
cut(h, x, y)
remove x from
the child list of y, decrementing y.degree
add x to
the root list of h
x.p = nil
x.mark = false
cascading_cut(h, y)
z = y.p
if z ≠ nil
if y.mark == false
y.mark = true
else
cut(h, y, z)
cascading_cut(h, z)
cut過程「切斷」x與其父結點y之間的鏈結,使x成為根結點。
我們使用mark屬性來得到需要的時間界。該屬性記錄了每個結點的一小段歷史。假定下面的步驟已經發生在結點x上:
1. 在某個時刻,x是根。
2. 然後x被鏈結到另乙個結點(成為孩子結點)。
3. 然後x的兩個孩子被切斷操作移除。
一旦失掉第二個孩子,就切斷x與其父結點的鏈結,使它成為乙個新的根。
假定在斐波那切堆中任何關鍵字的當前值均不為-∞。
fib_heap_delete(h, x)
fib_heap_decrease_key(h, x, -∞)
fib_heap_extract_min(h)
fib_heap_delete把唯一的最小關鍵字-∞賦予x,將x變為斐波那切堆中最小的結點。然後fib_heap_extract_min過程從斐波那切堆中移除x。 斐波那契堆
以下是實現的程式 肯定可以再優化的。include include include include using namespace std class node delete m child m child null class fibonacciheap node insert int key v...
斐波那契堆
ifndef finbonacci heap h define finbonacci heap h include stdlib.h include math.h define error0 printf error at file s line d n file line 定義乙個求有符號的無窮大...
斐波那契堆
斐波那契堆同二項堆一樣,也是一種可合併堆。相對於二項堆,斐波那契堆的優勢在於如果不涉及刪除元素的操作,則它的平攤執行時間為o 1 但是由於其演算法過於複雜,因而實際上更多的是用二項堆。乙個斐波那契堆具有如下性質 堆有一組有序樹組成,但是堆中的樹不一定是二項樹 斐波那契堆中的樹之間是無序的 二項堆中的...