|
1 | | ---- |
2 | | -title: 『数据结构』Fibonacci-heap |
3 | | -date: 2018-09-06 19:09 |
4 | | -categories: 数据结构与算法 |
5 | | -tags: [数据结构,斐波那契堆] |
6 | | -keywords: 数据结构,斐波那契堆 |
7 | | -mathjax: true |
8 | | -description: "介绍 fibnacci heap 的原理" |
9 | | ---- |
10 | | - |
11 | | -<!-- TOC --> |
12 | | - |
13 | | -- [1. 结构](#1-结构) |
14 | | -- [2. 势函数](#2-势函数) |
15 | | -- [3. 最大度数](#3-最大度数) |
16 | | -- [4. 操作](#4-操作) |
17 | | - - [4.1. 创建一个斐波那契堆](#41-创建一个斐波那契堆) |
18 | | - - [4.2. 插入一个结点](#42-插入一个结点) |
19 | | - - [4.3. 寻找最小结点](#43-寻找最小结点) |
20 | | - - [4.4. 合并两个斐波那契堆](#44-合并两个斐波那契堆) |
21 | | - - [4.5. 抽取最小值](#45-抽取最小值) |
22 | | - - [4.6. 关键字减值](#46-关键字减值) |
23 | | - - [4.7. 删除结点](#47-删除结点) |
24 | | -- [5. 最大度数的证明](#5-最大度数的证明) |
25 | | - |
26 | | -<!-- /TOC --> |
27 | | - |
28 | | - |
29 | | - |
30 | | -<a id="markdown-1-结构" name="1-结构"></a> |
31 | | -# 1. 结构 |
32 | | -斐波那契堆是一系列具有最小堆序的有根树的集合, 同一代(层)结点由双向循环链表链接, **为了便于删除最小结点, 还需要维持链表为升序, 即nd<=nd.right(nd==nd.right时只有一个结点或为 None)**, 父子之间都有指向对方的指针. |
33 | | - |
34 | | -结点有degree 属性, 记录孩子的个数, mark 属性用来标记(为了满足势函数, 达到摊还需求的) |
35 | | - |
36 | | -还有一个最小值指针 H.min 指向最小根结点 |
37 | | - |
38 | | - |
39 | | -<a id="markdown-2-势函数" name="2-势函数"></a> |
40 | | -# 2. 势函数 |
41 | | -下面用势函数来分析摊还代价, 如果你不明白, 可以看[摊还分析](https://www.jianshu.com/p/052fbe9d92a4) |
42 | | - |
43 | | -$\Phi(H) = t(H) + 2m(h)$ |
44 | | -t 是根链表中树的数目,m(H) 表示被标记的结点数 |
45 | | - |
46 | | -最初没有结点 |
47 | | -<a id="markdown-3-最大度数" name="3-最大度数"></a> |
48 | | -# 3. 最大度数 |
49 | | -结点的最大度数(即孩子数)$D(n)\leqslant \lfloor lgn \rfloor$, 证明放在最后 |
50 | | -<a id="markdown-4-操作" name="4-操作"></a> |
51 | | -# 4. 操作 |
52 | | -<a id="markdown-41-创建一个斐波那契堆" name="41-创建一个斐波那契堆"></a> |
53 | | -## 4.1. 创建一个斐波那契堆 |
54 | | -$O(1)$ |
55 | | -<a id="markdown-42-插入一个结点" name="42-插入一个结点"></a> |
56 | | -## 4.2. 插入一个结点 |
57 | | -```python |
58 | | -nd = new node |
59 | | -nd.prt = nd.chd = None |
60 | | -if H.min is None: |
61 | | - creat H with nd |
62 | | - H.min = nd |
63 | | -else: |
64 | | - insert nd into H's root list |
65 | | - if H.min<nd: H.min = nd |
66 | | -H.n +=1 |
67 | | -``` |
68 | | -$$ |
69 | | -\Delta \Phi = \Delta t(H) + 2\Delta m(H) = 1+0 = 1 |
70 | | -$$ |
71 | | -摊还代价为$O(1)$ |
72 | | -<a id="markdown-43-寻找最小结点" name="43-寻找最小结点"></a> |
73 | | -## 4.3. 寻找最小结点 |
74 | | -直接用 H.min, $O(1)$ |
75 | | -<a id="markdown-44-合并两个斐波那契堆" name="44-合并两个斐波那契堆"></a> |
76 | | -## 4.4. 合并两个斐波那契堆 |
77 | | -```python |
78 | | -def union(H1,H2): |
79 | | - if H1.min ==None or (H1.min and H2.min and H1.min>H2.min): |
80 | | - H1.min = H2.min |
81 | | - link H2.rootList to H1.rootList |
82 | | - return H1 |
83 | | -``` |
84 | | -易知 $\Delta \Phi = 0$ |
85 | | -<a id="markdown-45-抽取最小值" name="45-抽取最小值"></a> |
86 | | -## 4.5. 抽取最小值 |
87 | | -抽取最小值, 一定是在根结点, 然后将此根结点的所有子树的根放在 根结点双向循环链表中, 之后还要进行**树的合并. 以使每个根结点的度不同,** |
88 | | -```python |
89 | | -def extract-min(H): |
90 | | - z = H.min |
91 | | - if z!=None: |
92 | | - for chd of z: |
93 | | - link chd to H.rootList |
94 | | - chd.prt = None |
95 | | - remove z from the rootList of H |
96 | | - if z==z.right: |
97 | | - H.min = None |
98 | | - else: |
99 | | - H.min = z.right |
100 | | - consolidate(H) |
101 | | - H.n -=1 |
102 | | - return z |
103 | | -``` |
104 | | -consolidate 函数使用一个 辅助数组degree来记录所有根结点(不超过lgn)对应的度数, degree[i] = nd 表示.有且只有一个结点 nd 的度数为 i. |
105 | | -```python |
106 | | -def consolidate(H): |
107 | | - initialize degree with None |
108 | | - for nd in H.rootList: |
109 | | - d = nd.degree |
110 | | - while degree[d] !=None: |
111 | | - nd2 = degree[d] |
112 | | - if nd2.degree < nd.degree: |
113 | | - nd2,nd = nd,nd2 |
114 | | - |
115 | | - make nd2 child of nd |
116 | | - nd.degree = d+1 |
117 | | - nd.mark = False # to balace the potential |
118 | | - |
119 | | - remove nd2 from H.rootList |
120 | | - degree[d] = None |
121 | | - d+=1 |
122 | | - else: degree[d] = nd |
123 | | - for i in degree: |
124 | | - if i!=None: |
125 | | - link i to H.rootList |
126 | | - if H.min ==None: H.min = i |
127 | | - else if H.min>i: H.min = i |
128 | | -``` |
129 | | -时间复杂度为$O(lgn)$ 即数组移动的长度, 而最多有 lgn个元素 |
130 | | - |
131 | | -<a id="markdown-46-关键字减值" name="46-关键字减值"></a> |
132 | | -## 4.6. 关键字减值 |
133 | | -```python |
134 | | -def decrease-key(H,x,k): |
135 | | - if k>x.key: error |
136 | | - x.key = k |
137 | | - y=x.p |
138 | | - if y!=None and x.key < y.key: |
139 | | - cut(H,x,y) |
140 | | - cascading-cut(H,y) |
141 | | - if x.key < H.min.key: |
142 | | - H.min = x |
143 | | -def cut(H,x,y): |
144 | | - remove x from the child list of y, decrementing y.degree |
145 | | - add x to H.rootList |
146 | | - x.prt = None |
147 | | - x.mark = False |
148 | | - |
149 | | -def cascading-cut(H,y): |
150 | | - z- y,prt |
151 | | - if z !=None: |
152 | | - if y.mark ==False:y.mark = True |
153 | | - else: |
154 | | - cut(H,y,z) |
155 | | - cascading-cut(H,z) |
156 | | -``` |
157 | | - |
158 | | - |
159 | | -<a id="markdown-47-删除结点" name="47-删除结点"></a> |
160 | | -## 4.7. 删除结点 |
161 | | -```python |
162 | | -decrease(H,nd, MIN) |
163 | | -extract-min(H) |
164 | | -``` |
165 | | - |
166 | | -<a id="markdown-5-最大度数的证明" name="5-最大度数的证明"></a> |
167 | | -# 5. 最大度数的证明 |
168 | | -这也是`斐波那契`这个名字的由来, |
169 | | -$D(n)\leqslant \lfloor lgn \rfloor$ |
170 | | - |
| 1 | +--- |
| 2 | +title: 『数据结构』Fibonacci-heap |
| 3 | +date: 2018-09-06 19:09 |
| 4 | +categories: 数据结构与算法 |
| 5 | +tags: [数据结构,斐波那契堆] |
| 6 | +keywords: 数据结构,斐波那契堆 |
| 7 | +mathjax: true |
| 8 | +description: "介绍 fibnacci heap 的原理" |
| 9 | +--- |
| 10 | + |
| 11 | +<!-- TOC --> |
| 12 | + |
| 13 | +- [1. 结构](#1-结构) |
| 14 | +- [2. 势函数](#2-势函数) |
| 15 | +- [3. 最大度数](#3-最大度数) |
| 16 | +- [4. 操作](#4-操作) |
| 17 | + - [4.1. 创建一个斐波那契堆](#41-创建一个斐波那契堆) |
| 18 | + - [4.2. 插入一个结点](#42-插入一个结点) |
| 19 | + - [4.3. 寻找最小结点](#43-寻找最小结点) |
| 20 | + - [4.4. 合并两个斐波那契堆](#44-合并两个斐波那契堆) |
| 21 | + - [4.5. 抽取最小值](#45-抽取最小值) |
| 22 | + - [4.6. 关键字减值](#46-关键字减值) |
| 23 | + - [4.7. 删除结点](#47-删除结点) |
| 24 | +- [5. 最大度数的证明](#5-最大度数的证明) |
| 25 | + |
| 26 | +<!-- /TOC --> |
| 27 | + |
| 28 | + |
| 29 | + |
| 30 | +<a id="markdown-1-结构" name="1-结构"></a> |
| 31 | +# 1. 结构 |
| 32 | +斐波那契堆是一系列具有最小堆序的有根树的集合, 同一代(层)结点由双向循环链表链接, **为了便于删除最小结点, 还需要维持链表为升序, 即nd<=nd.right(nd==nd.right时只有一个结点或为 None)**, 父子之间都有指向对方的指针. |
| 33 | + |
| 34 | +结点有degree 属性, 记录孩子的个数, mark 属性用来标记(为了满足势函数, 达到摊还需求的) |
| 35 | + |
| 36 | +还有一个最小值指针 H.min 指向最小根结点 |
| 37 | + |
| 38 | + |
| 39 | +<a id="markdown-2-势函数" name="2-势函数"></a> |
| 40 | +# 2. 势函数 |
| 41 | +下面用势函数来分析摊还代价, 如果你不明白, 可以看[摊还分析](https://www.jianshu.com/p/052fbe9d92a4) |
| 42 | + |
| 43 | +&space;=&space;t(H)&space;+&space;2m(h)) |
| 44 | +t 是根链表中树的数目,m(H) 表示被标记的结点数 |
| 45 | + |
| 46 | +最初没有结点 |
| 47 | +<a id="markdown-3-最大度数" name="3-最大度数"></a> |
| 48 | +# 3. 最大度数 |
| 49 | +结点的最大度数(即孩子数)\leqslant&space;\lfloor&space;lgn&space;\rfloor), 证明放在最后 |
| 50 | +<a id="markdown-4-操作" name="4-操作"></a> |
| 51 | +# 4. 操作 |
| 52 | +<a id="markdown-41-创建一个斐波那契堆" name="41-创建一个斐波那契堆"></a> |
| 53 | +## 4.1. 创建一个斐波那契堆 |
| 54 | +) |
| 55 | +<a id="markdown-42-插入一个结点" name="42-插入一个结点"></a> |
| 56 | +## 4.2. 插入一个结点 |
| 57 | +```python |
| 58 | +nd = new node |
| 59 | +nd.prt = nd.chd = None |
| 60 | +if H.min is None: |
| 61 | + creat H with nd |
| 62 | + H.min = nd |
| 63 | +else: |
| 64 | + insert nd into H's root list |
| 65 | + if H.min<nd: H.min = nd |
| 66 | +H.n +=1 |
| 67 | +``` |
| 68 | +&space;+&space;2\Delta&space;m(H)&space;=&space;1+0&space;=&space;1&space;) |
| 69 | +摊还代价为) |
| 70 | +<a id="markdown-43-寻找最小结点" name="43-寻找最小结点"></a> |
| 71 | +## 4.3. 寻找最小结点 |
| 72 | +直接用 H.min, ) |
| 73 | +<a id="markdown-44-合并两个斐波那契堆" name="44-合并两个斐波那契堆"></a> |
| 74 | +## 4.4. 合并两个斐波那契堆 |
| 75 | +```python |
| 76 | +def union(H1,H2): |
| 77 | + if H1.min ==None or (H1.min and H2.min and H1.min>H2.min): |
| 78 | + H1.min = H2.min |
| 79 | + link H2.rootList to H1.rootList |
| 80 | + return H1 |
| 81 | +``` |
| 82 | +易知  |
| 83 | +<a id="markdown-45-抽取最小值" name="45-抽取最小值"></a> |
| 84 | +## 4.5. 抽取最小值 |
| 85 | +抽取最小值, 一定是在根结点, 然后将此根结点的所有子树的根放在 根结点双向循环链表中, 之后还要进行**树的合并. 以使每个根结点的度不同,** |
| 86 | +```python |
| 87 | +def extract-min(H): |
| 88 | + z = H.min |
| 89 | + if z!=None: |
| 90 | + for chd of z: |
| 91 | + link chd to H.rootList |
| 92 | + chd.prt = None |
| 93 | + remove z from the rootList of H |
| 94 | + if z==z.right: |
| 95 | + H.min = None |
| 96 | + else: |
| 97 | + H.min = z.right |
| 98 | + consolidate(H) |
| 99 | + H.n -=1 |
| 100 | + return z |
| 101 | +``` |
| 102 | +consolidate 函数使用一个 辅助数组degree来记录所有根结点(不超过lgn)对应的度数, degree[i] = nd 表示.有且只有一个结点 nd 的度数为 i. |
| 103 | +```python |
| 104 | +def consolidate(H): |
| 105 | + initialize degree with None |
| 106 | + for nd in H.rootList: |
| 107 | + d = nd.degree |
| 108 | + while degree[d] !=None: |
| 109 | + nd2 = degree[d] |
| 110 | + if nd2.degree < nd.degree: |
| 111 | + nd2,nd = nd,nd2 |
| 112 | + |
| 113 | + make nd2 child of nd |
| 114 | + nd.degree = d+1 |
| 115 | + nd.mark = False # to balace the potential |
| 116 | + |
| 117 | + remove nd2 from H.rootList |
| 118 | + degree[d] = None |
| 119 | + d+=1 |
| 120 | + else: degree[d] = nd |
| 121 | + for i in degree: |
| 122 | + if i!=None: |
| 123 | + link i to H.rootList |
| 124 | + if H.min ==None: H.min = i |
| 125 | + else if H.min>i: H.min = i |
| 126 | +``` |
| 127 | +时间复杂度为) 即数组移动的长度, 而最多有 lgn个元素 |
| 128 | + |
| 129 | +<a id="markdown-46-关键字减值" name="46-关键字减值"></a> |
| 130 | +## 4.6. 关键字减值 |
| 131 | +```python |
| 132 | +def decrease-key(H,x,k): |
| 133 | + if k>x.key: error |
| 134 | + x.key = k |
| 135 | + y=x.p |
| 136 | + if y!=None and x.key < y.key: |
| 137 | + cut(H,x,y) |
| 138 | + cascading-cut(H,y) |
| 139 | + if x.key < H.min.key: |
| 140 | + H.min = x |
| 141 | +def cut(H,x,y): |
| 142 | + remove x from the child list of y, decrementing y.degree |
| 143 | + add x to H.rootList |
| 144 | + x.prt = None |
| 145 | + x.mark = False |
| 146 | + |
| 147 | +def cascading-cut(H,y): |
| 148 | + z- y,prt |
| 149 | + if z !=None: |
| 150 | + if y.mark ==False:y.mark = True |
| 151 | + else: |
| 152 | + cut(H,y,z) |
| 153 | + cascading-cut(H,z) |
| 154 | +``` |
| 155 | + |
| 156 | + |
| 157 | +<a id="markdown-47-删除结点" name="47-删除结点"></a> |
| 158 | +## 4.7. 删除结点 |
| 159 | +```python |
| 160 | +decrease(H,nd, MIN) |
| 161 | +extract-min(H) |
| 162 | +``` |
| 163 | + |
| 164 | +<a id="markdown-5-最大度数的证明" name="5-最大度数的证明"></a> |
| 165 | +# 5. 最大度数的证明 |
| 166 | +这也是`斐波那契`这个名字的由来, |
| 167 | +\leqslant&space;\lfloor&space;lgn&space;\rfloor) |
| 168 | + |
0 commit comments