|
25 | 25 | 1. 每个节点的Key大于(或小于)子节点的Key |
26 | 26 | 2. 对于任意节点的左右两个子节点,右子节点的`npl`不大于左子节点的`npl`. |
27 | 27 |
|
28 | | -可以证明 如果一个左倾堆的右侧路径上有r个节点,那么该左倾堆将至少有2^r-1个节点,整个左倾堆至少有2^(r+1)-1个节点,因此如果沿着右侧路径合并,复杂度 |
| 28 | +可以证明 如果一个左倾堆的右侧路径上有r个节点,那么该左倾堆将至少有2^r-1个节点,整个左倾堆至少有2^(r+1)-1个节点,因此如果沿着右侧路径合并,复杂度 |
29 | 29 | 为log(n). |
30 | 30 |
|
31 | 31 | 左倾堆合并算法: |
|
54 | 54 | * 每个节点只有一个孩子指针,指向第一个孩子 |
55 | 55 | * 每个节点有一个邻居指针,指向下一个邻居,通过孩子指针和孩子指针的邻居指针可以遍历所有的孩子. |
56 | 56 |
|
57 | | - |
| 57 | + |
58 | 58 |
|
59 | 59 | 二项堆是指满足以下性质的二项树的集合: |
60 | 60 |
|
|
67 | 67 |
|
68 | 68 | 最基本的为二个度数相同的二项树的合并,由于二项树根结点包含最小的关键字,因此在二颗树合并时,只需比较二个根结点关键字的大小,其中含小关键字的结点成为结果树的根结点,另一棵树则变成结果树的子树 |
69 | 69 |
|
| 70 | +```js |
| 71 | +function mergeTree(p, q) |
| 72 | + if p.root <= q.root |
| 73 | + return p.addSubTree(q) |
| 74 | + else |
| 75 | + return q.addSubTree(p) |
| 76 | +``` |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | +两个二项堆的合并则可按如下步骤进行:度数 j从小取到大,在两个二项堆中如果其中只有一棵树的度数为 j,即将此树移动到结果堆,而如果只两棵树的度数都为 j,则根据以上方法合并为一个度数为 j+1 的二项树.此后这个度数为 j+1 的树将可能会和其他度数为 j+1 的二项树进行合并.因此,对于任何度数j,可能最多需要合并3棵二项树. |
| 81 | + |
| 82 | +此操作的时间复杂度为 O(log n). |
| 83 | + |
| 84 | +```js |
| 85 | +function merge(p, q) |
| 86 | + while not (p.end() and q.end()) |
| 87 | + tree = mergeTree(p.currentTree(), q.currentTree()) |
| 88 | + if not heap.currentTree().empty() |
| 89 | + tree = mergeTree(tree, heap.currentTree()) |
| 90 | + heap.addTree(tree) |
| 91 | + heap.next(); p.next(); q.next() |
| 92 | +``` |
| 93 | + |
| 94 | + |
| 95 | + |
70 | 96 | ### 插入 |
71 | 97 |
|
72 | 98 | 创建一个只包含要插入元素的二项堆,再将此堆与原先的二项堆进行合并,即可得到插入后的堆.由于需要合并,插入操作需要O(logn)的时间.平摊分析的时间复杂度为O(1) |
|
79 | 105 |
|
80 | 106 | 先找到最小关键字所在结点,然后将它从其所在的二项树中删除,并获得其子树,将这些子树看作一个独立的二项堆,再将此堆合并到原先的堆中即可 |
81 | 107 |
|
| 108 | +```js |
| 109 | +function deleteMin(heap) |
| 110 | + min = heap.trees().first() |
| 111 | + for each current in heap.trees() |
| 112 | + if current.root < min then min = current |
| 113 | + for each tree in min.subTrees() |
| 114 | + tmp.addTree(tree) |
| 115 | + heap.removeTree(min) |
| 116 | + merge(heap, tmp) |
| 117 | +``` |
| 118 | + |
82 | 119 | ### 减小特定结点(关键字)的值 |
83 | 120 |
|
84 | 121 | 在减小特定结点(关键字)的值后,可能会不满足最小堆积性质.此时,将其所在结点与父结点交换,如还不满足最小堆性质则再与祖父结点交换……直到最小堆性质得到满足. |
|
87 | 124 |
|
88 | 125 | 将需要删除的结点的关键字的值减小到负无穷大(比二项堆中的其他所有关键字的值都小即可),执行“减小关键字的值”算法,使其调整到当前二项树的根节点位置,再删除最小关键字的根结点即可 |
89 | 126 |
|
| 127 | +以下对于二项堆操作的运行时间都为 O(logn): |
| 128 | + |
| 129 | +* 在二项堆中插入新结点 |
| 130 | +* 合并两个二项堆 |
| 131 | +* 查找最小关键字所在结点(可以通过维护最小关键字指针达到 O(1)) |
| 132 | +* 删除最小关键字所在结点 |
| 133 | +* 减小给定结点关键字的值 |
| 134 | +* 删除给定结点 |
| 135 | + |
90 | 136 | ## 斐波那契堆(Fibonacci Heap) |
91 | 137 |
|
92 | | -斐波那契堆是一系列无序树的集合,每棵树是一个最小堆,满足最小堆的性质.堆保存了堆中所有节点的数目,保存了最小关键字的节点. |
| 138 | +斐波那契堆是由一组最小堆有序树构成的集合,每个最小堆有序树的度数为其子节点的数目,树的度数为其根节点的度数. |
93 | 139 |
|
94 | 140 | 斐波那契堆中所有树的根节点也用一个双向循环链表链接起来 |
95 | 141 |
|
96 | 142 | 使用一个指针指向斐波那契堆中最小元素 |
97 | 143 |
|
| 144 | +斐波那契堆 比二项堆有更好的平摊分析复杂度 |
| 145 | + |
98 | 146 |  |
99 | 147 |
|
| 148 | +斐波那契堆的主要操作有: |
| 149 | + |
| 150 | +* 合并两个斐波那契堆(O(1)): 简单合并两个斐波纳契堆的根表.即把两个斐波纳契堆的所有树的根首尾衔接并置 |
| 151 | +* 在斐波那契堆中插入新结点(O(1)): 创建一个仅包含一个节点的新的斐波纳契堆,然后执行堆合并. |
| 152 | +* 查找最小关键字所在结点(O(1)): 由于用一个指针指向了具有最小值的根节点,因此查找最小的节点是简单的操作. |
| 153 | +* 删除最小关键字所在结点(平摊分析 O(log(n))): 查找最小的根节点并删除它,其所有的子节点都加入堆的根表,然后维护根表(维护根表: 然后对根表中当前包含的树的度数从低到高,迭代执行具有相同度数的树的合并并实现最小树化调整,使得堆包含的树具有不同的度数) |
| 154 | +* 减小给定结点关键字的值(平摊分析 O(1)): 对一个节点的键值降低后,自键值降低的节点开始自下而上的迭代执行下述操作,直至到根节点或一个未被标记(marked)节点为止 |
| 155 | + 如果当前节点键值小于其父节点的键值,则把该节点及其子树摘下来作为堆的新树的根节点;其原父节点如果是被标记(marked)节点,则也被摘下来作为堆的新树的根节点;如果其原父节点不是被标记(marked)节点且不是根节点,则其原父节点被加标记. |
| 156 | +* 删除给定结点(平摊分析 O(log(n))): 把被删除节点的键值调整为负无穷小,然后减小给定结点关键字的值,然后再删除最小关键字所在结点 |
| 157 | + |
100 | 158 | ## 优先队列(Priority Queue) |
101 | 159 |
|
102 | | -普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有最高级先出(**first in, largest out**)的行为特征.通常采用堆数据结构来实现. |
| 160 | +普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有最高级先出(**first in, largest out**)的行为特征.通常采用堆(例如二项堆,斐波那契堆等)数据结构来实现. |
| 161 | + |
| 162 | +## Reference |
| 163 | + |
| 164 | +[binomial-heap/overview](https://www.growingwiththeweb.com/data-structures/binomial-heap/overview/) |
| 165 | +[fibonacci-heap/overview](https://www.growingwiththeweb.com/data-structures/fibonacci-heap/overview/) |
0 commit comments