斐波那契堆

2021-07-27 05:56:22 字數 4925 閱讀 5920

斐波那切堆資料結構有兩種用途。第一種,它支援一系列操作,這些操作構成了所謂的「可合併堆」;第二種,斐波那切堆的一些操作可以在常數攤還時間內完成,這使得這種資料結構非常適合於需要頻繁呼叫這些操作的應用。

可合併堆是支援以下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 但是由於其演算法過於複雜,因而實際上更多的是用二項堆。乙個斐波那契堆具有如下性質 堆有一組有序樹組成,但是堆中的樹不一定是二項樹 斐波那契堆中的樹之間是無序的 二項堆中的...