|
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