二项堆

在计算机科学中,二项堆(Binomial Heap)是一种堆结构。与二叉堆(Binary Heap)相比,其优势是可以快速合并两个堆,因此它属于可合并堆(Mergeable Heap)数据结构的一种。

可合并堆通常支持下面几种操作:

  • Make-Heap():创建并返回一个不包含任何元素的新堆。
  • Insert(H, x):将节点 x 插入到堆 H 中。
  • Minimum(H):返回堆 H 中的最小关键字。
  • Extract-Min(H):将堆 H 中包含最小关键字的节点删除。
  • Union(H1, H2):创建并返回一个包含 H1和 H2 的新堆。
  • Decrease-Key(H, x, k):将新关键字 k 赋给堆 H 中的节点 x。
  • Delete(H, x):从堆 H 中删除 节点 x。

二项树

一个二项堆由一组二项树所构成,二项树是一种特殊的多分支有序树,如下图 (a)。

二项树 Bk 是一种递归定义的有序树。二项树 B0 只包含一个结点。二项树 Bk 由两个子树 Bk-1 连接而成:其中一棵树的根是另一棵树的根的最左孩子。

二项树的性质有:

  1. 共有 2k 个节点。
  2. 树的高度为 k。
  3. 在深度 d 处恰有  个结点。
  4. 根的度数为 k,它大于任何其他节点的度数;如果根的子女从左到右的编号设为 k-1, k-2, …, 0,子女 i 是子树 Bi 的根。

上图 (b) 表示二项树 B0 至 B4 中各节点的深度。图 (c) 以另外一种方式来看二项树 Bk

在一棵包含 n 个节点的二项树中,任意节点的最大度数为 lgn。

二项堆

二项堆 H 由一组满足下面的二项堆性质的二项树组成。

  1. H 中的每个二项树遵循最小堆的性质:节点的关键字大于等于其父节点的关键字。
  2. 对于任意非负整数 k,在 H 中至多有一棵二项树的根具有度数 k。

第一个性质告诉我们,在一棵最小堆有序的二项树中,其根包含了树中最小的关键字。

第二个性质告诉我们,在包含 n 个节点的二项堆H中,包含至多 floor(lgn)+1 棵二项树。

比如上图中一个包含 13 个节点的二项堆 H。13的二进制表示为(1101),故 H 包含了最小堆有序二项树B3,B2 和 B0, 他们分别有 8,4 和 1 个节点,即共有 13 个节点。

代码示例

  1 /* heap.h -- Binomial Heaps
  2  *
  3  * Copyright (c) 2008, Bjoern B. Brandenburg <bbb [at] cs.unc.edu>
  4  *
  5  * All rights reserved.
  6  *
  7  * Redistribution and use in source and binary forms, with or without
  8  * modification, are permitted provided that the following conditions are met:
  9  *     * Redistributions of source code must retain the above copyright
 10  *       notice, this list of conditions and the following disclaimer.
 11  *     * Redistributions in binary form must reproduce the above copyright
 12  *       notice, this list of conditions and the following disclaimer in the
 13  *       documentation and/or other materials provided with the distribution.
 14  *     * Neither the name of the University of North Carolina nor the
 15  *       names of its contributors may be used to endorse or promote products
 16  *       derived from this software without specific prior written permission.
 17  *
 18  * THIS SOFTWARE IS PROVIDED BY  COPYRIGHT OWNER AND CONTRIBUTERS ``AS IS‘‘ AND
 19  * ANY  EXPRESS OR  IMPLIED  WARRANTIES,  INCLUDING, BUT  NOT  LIMITED TO,  THE
 20  * IMPLIED WARRANTIES  OF MERCHANTABILITY AND FITNESS FOR  A PARTICULAR PURPOSE
 21  * ARE DISCLAIMED.  IN NO  EVENT SHALL THE  COPYRIGHT OWNER OR  CONTRIBUTERS BE
 22  * LIABLE  FOR  ANY  DIRECT,   INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
 23  * CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT  LIMITED  TO,  PROCUREMENT  OF
 24  * SUBSTITUTE GOODS  OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
 25  * INTERRUPTION)  HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN
 26  * CONTRACT,  STRICT LIABILITY,  OR  TORT (INCLUDING  NEGLIGENCE OR  OTHERWISE)
 27  * ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
 28  * POSSIBILITY OF SUCH DAMAGE.
 29  */
 30
 31 #ifndef HEAP_H
 32 #define HEAP_H
 33
 34 #define NOT_IN_HEAP UINT_MAX
 35
 36 struct heap_node {
 37     struct heap_node*     parent;
 38     struct heap_node*     next;
 39     struct heap_node*     child;
 40
 41     unsigned int         degree;
 42     void*            value;
 43     struct heap_node**    ref;
 44 };
 45
 46 struct heap {
 47     struct heap_node*     head;
 48     /* We cache the minimum of the heap.
 49      * This speeds up repeated peek operations.
 50      */
 51     struct heap_node*    min;
 52 };
 53
 54 /* item comparison function:
 55  * return 1 if a has higher prio than b, 0 otherwise
 56  */
 57 typedef int (*heap_prio_t)(struct heap_node* a, struct heap_node* b);
 58
 59 static inline void heap_init(struct heap* heap)
 60 {
 61     heap->head = NULL;
 62     heap->min  = NULL;
 63 }
 64
 65 static inline void heap_node_init_ref(struct heap_node** _h, void* value)
 66 {
 67     struct heap_node* h = *_h;
 68     h->parent = NULL;
 69     h->next   = NULL;
 70     h->child  = NULL;
 71     h->degree = NOT_IN_HEAP;
 72     h->value  = value;
 73     h->ref    = _h;
 74 }
 75
 76 static inline void heap_node_init(struct heap_node* h, void* value)
 77 {
 78     h->parent = NULL;
 79     h->next   = NULL;
 80     h->child  = NULL;
 81     h->degree = NOT_IN_HEAP;
 82     h->value  = value;
 83     h->ref    = NULL;
 84 }
 85
 86 static inline void* heap_node_value(struct heap_node* h)
 87 {
 88     return h->value;
 89 }
 90
 91 static inline int heap_node_in_heap(struct heap_node* h)
 92 {
 93     return h->degree != NOT_IN_HEAP;
 94 }
 95
 96 static inline int heap_empty(struct heap* heap)
 97 {
 98     return heap->head == NULL && heap->min == NULL;
 99 }
100
101 /* make child a subtree of root */
102 static inline void __heap_link(struct heap_node* root,
103                    struct heap_node* child)
104 {
105     child->parent = root;
106     child->next   = root->child;
107     root->child   = child;
108     root->degree++;
109 }
110
111 /* merge root lists */
112 static inline struct heap_node* __heap_merge(struct heap_node* a,
113                          struct heap_node* b)
114 {
115     struct heap_node* head = NULL;
116     struct heap_node** pos = &head;
117
118     while (a && b) {
119         if (a->degree < b->degree) {
120             *pos = a;
121             a = a->next;
122         } else {
123             *pos = b;
124             b = b->next;
125         }
126         pos = &(*pos)->next;
127     }
128     if (a)
129         *pos = a;
130     else
131         *pos = b;
132     return head;
133 }
134
135 /* reverse a linked list of nodes. also clears parent pointer */
136 static inline struct heap_node* __heap_reverse(struct heap_node* h)
137 {
138     struct heap_node* tail = NULL;
139     struct heap_node* next;
140
141     if (!h)
142         return h;
143
144     h->parent = NULL;
145     while (h->next) {
146         next    = h->next;
147         h->next = tail;
148         tail    = h;
149         h       = next;
150         h->parent = NULL;
151     }
152     h->next = tail;
153     return h;
154 }
155
156 static inline void __heap_min(heap_prio_t higher_prio, struct heap* heap,
157                   struct heap_node** prev, struct heap_node** node)
158 {
159     struct heap_node *_prev, *cur;
160     *prev = NULL;
161
162     if (!heap->head) {
163         *node = NULL;
164         return;
165     }
166
167     *node = heap->head;
168     _prev = heap->head;
169     cur   = heap->head->next;
170     while (cur) {
171         if (higher_prio(cur, *node)) {
172             *node = cur;
173             *prev = _prev;
174         }
175         _prev = cur;
176         cur   = cur->next;
177     }
178 }
179
180 static inline void __heap_union(heap_prio_t higher_prio, struct heap* heap,
181                 struct heap_node* h2)
182 {
183     struct heap_node* h1;
184     struct heap_node *prev, *x, *next;
185     if (!h2)
186         return;
187     h1 = heap->head;
188     if (!h1) {
189         heap->head = h2;
190         return;
191     }
192     h1 = __heap_merge(h1, h2);
193     prev = NULL;
194     x    = h1;
195     next = x->next;
196     while (next) {
197         if (x->degree != next->degree ||
198             (next->next && next->next->degree == x->degree)) {
199             /* nothing to do, advance */
200             prev = x;
201             x    = next;
202         } else if (higher_prio(x, next)) {
203             /* x becomes the root of next */
204             x->next = next->next;
205             __heap_link(x, next);
206         } else {
207             /* next becomes the root of x */
208             if (prev)
209                 prev->next = next;
210             else
211                 h1 = next;
212             __heap_link(next, x);
213             x = next;
214         }
215         next = x->next;
216     }
217     heap->head = h1;
218 }
219
220 static inline struct heap_node* __heap_extract_min(heap_prio_t higher_prio,
221                            struct heap* heap)
222 {
223     struct heap_node *prev, *node;
224     __heap_min(higher_prio, heap, &prev, &node);
225     if (!node)
226         return NULL;
227     if (prev)
228         prev->next = node->next;
229     else
230         heap->head = node->next;
231     __heap_union(higher_prio, heap, __heap_reverse(node->child));
232     return node;
233 }
234
235 /* insert (and reinitialize) a node into the heap */
236 static inline void heap_insert(heap_prio_t higher_prio, struct heap* heap,
237                    struct heap_node* node)
238 {
239     struct heap_node *min;
240     node->child  = NULL;
241     node->parent = NULL;
242     node->next   = NULL;
243     node->degree = 0;
244     if (heap->min && higher_prio(node, heap->min)) {
245         /* swap min cache */
246         min = heap->min;
247         min->child  = NULL;
248         min->parent = NULL;
249         min->next   = NULL;
250         min->degree = 0;
251         __heap_union(higher_prio, heap, min);
252         heap->min   = node;
253     } else
254         __heap_union(higher_prio, heap, node);
255 }
256
257 static inline void __uncache_min(heap_prio_t higher_prio, struct heap* heap)
258 {
259     struct heap_node* min;
260     if (heap->min) {
261         min = heap->min;
262         heap->min = NULL;
263         heap_insert(higher_prio, heap, min);
264     }
265 }
266
267 /* merge addition into target */
268 static inline void heap_union(heap_prio_t higher_prio,
269                   struct heap* target, struct heap* addition)
270 {
271     /* first insert any cached minima, if necessary */
272     __uncache_min(higher_prio, target);
273     __uncache_min(higher_prio, addition);
274     __heap_union(higher_prio, target, addition->head);
275     /* this is a destructive merge */
276     addition->head = NULL;
277 }
278
279 static inline struct heap_node* heap_peek(heap_prio_t higher_prio,
280                       struct heap* heap)
281 {
282     if (!heap->min)
283         heap->min = __heap_extract_min(higher_prio, heap);
284     return heap->min;
285 }
286
287 static inline struct heap_node* heap_take(heap_prio_t higher_prio,
288                       struct heap* heap)
289 {
290     struct heap_node *node;
291     if (!heap->min)
292         heap->min = __heap_extract_min(higher_prio, heap);
293     node = heap->min;
294     heap->min = NULL;
295     if (node)
296         node->degree = NOT_IN_HEAP;
297     return node;
298 }
299
300 static inline void heap_decrease(heap_prio_t higher_prio, struct heap* heap,
301                  struct heap_node* node)
302 {
303     struct heap_node *parent;
304     struct heap_node** tmp_ref;
305     void* tmp;
306
307     /* node‘s priority was decreased, we need to update its position */
308     if (!node->ref)
309         return;
310     if (heap->min != node) {
311         if (heap->min && higher_prio(node, heap->min))
312             __uncache_min(higher_prio, heap);
313         /* bubble up */
314         parent = node->parent;
315         while (parent && higher_prio(node, parent)) {
316             /* swap parent and node */
317             tmp           = parent->value;
318             parent->value = node->value;
319             node->value   = tmp;
320             /* swap references */
321             if (parent->ref)
322                 *(parent->ref) = node;
323             *(node->ref)   = parent;
324             tmp_ref        = parent->ref;
325             parent->ref    = node->ref;
326             node->ref      = tmp_ref;
327             /* step up */
328             node   = parent;
329             parent = node->parent;
330         }
331     }
332 }
333
334 static inline void heap_delete(heap_prio_t higher_prio, struct heap* heap,
335                    struct heap_node* node)
336 {
337     struct heap_node *parent, *prev, *pos;
338     struct heap_node** tmp_ref;
339     void* tmp;
340
341     if (!node->ref) /* can only delete if we have a reference */
342         return;
343     if (heap->min != node) {
344         /* bubble up */
345         parent = node->parent;
346         while (parent) {
347             /* swap parent and node */
348             tmp           = parent->value;
349             parent->value = node->value;
350             node->value   = tmp;
351             /* swap references */
352             if (parent->ref)
353                 *(parent->ref) = node;
354             *(node->ref)   = parent;
355             tmp_ref        = parent->ref;
356             parent->ref    = node->ref;
357             node->ref      = tmp_ref;
358             /* step up */
359             node   = parent;
360             parent = node->parent;
361         }
362         /* now delete:
363          * first find prev */
364         prev = NULL;
365         pos  = heap->head;
366         while (pos != node) {
367             prev = pos;
368             pos  = pos->next;
369         }
370         /* we have prev, now remove node */
371         if (prev)
372             prev->next = node->next;
373         else
374             heap->head = node->next;
375         __heap_union(higher_prio, heap, __heap_reverse(node->child));
376     } else
377         heap->min = NULL;
378     node->degree = NOT_IN_HEAP;
379 }
380
381 #endif /* HEAP_H */

参考资料

时间: 2024-12-23 15:44:51

二项堆的相关文章

[硕.Love Python] BinomialHeap(B堆 & 二项堆)

class Node(object):     def __init__(self, data):         self.data = data         self.child = None         self.left = None         self.right = None         self.degree = 0     def __str__(self):         return str(self.data)     __repr__ = __str_

笔试算法题(46):简介 - 二叉堆 &amp; 二项树 &amp; 二项堆 &amp; 斐波那契堆

二叉堆(Binary Heap) 二叉堆是完全二叉树(或者近似完全二叉树):其满足堆的特性:父节点的值>=(<=)任何一个子节点的键值,并且每个左子树或者右子树都是一 个二叉堆(最小堆或者最大堆):一般使用数组构建二叉堆,对于array[i]而言,其左子节点为array[2*i],其右子节点为 array[2*i+1]:二叉堆支持插入,删除,查找最大(最小)键值的操作,但是合并二叉堆的复杂度较高,时间复杂度为O(N):但是二项堆或者斐波 那契堆则仅需要O(logN): 二项树(Binomial

二项堆(一)之 图文解析 和 C语言的实现

概要 本章介绍二项堆,它和之前所讲的堆(二叉堆.左倾堆.斜堆)一样,也是用于实现优先队列的.和以往一样,本文会先对二项堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理一样,选择其中之一进行了解即可.若文章有错误或不足的地方,请不吝指出! 目录1. 二项树的介绍2. 二项堆的介绍3. 二项堆的基本操作4. 二项堆的C实现(完整源码)5. 二项堆的C测试程序 转载请注明出处:http://www.cnblogs.com/skywan

算法导论 二项堆

可以合并的堆 二项堆 先看看堆得操作运行时间的对比 对于使用这种数据结构有个概念 二项堆在union操作合并上有优势 二项堆由二项树组成 我们先看看二项树的定义 因为性质3中的系数就是二项式分布的系数,所以二项树名由此得来 B0 有2º = 1个节点 B? 有2¹=2个节点 且根节点比子节点小 B? 有2²=4个节点 且根节点比子节点小 B? 有2³=8个节点 且根节点比子节点小 二项堆则按照以下规则有二项树组成 由图 因为二项堆都是最小堆有序的,最小节点必定在跟节点中,寻找最小关键字就比较简单

深度解析(十三)二项堆

二项堆(一)之 图文解析 和 C语言的实现 概要 本章介绍二项堆,它和之前所讲的堆(二叉堆.左倾堆.斜堆)一样,也是用于实现优先队列的.和以往一样,本文会先对二项堆的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理一样,选择其中之一进行了解即可.若文章有错误或不足的地方,请不吝指出! 目录1. 二项树的介绍2. 二项堆的介绍3. 二项堆的基本操作4. 二项堆的C实现(完整源码)5. 二项堆的C测试程序 转载请注明出处:http://

12、【堆】二项堆

一.二项树的介绍 二项树的定义 二项堆是二项树的集合.在了解二项堆之前,先对二项树进行介绍. 二项树是一种递归定义的有序树.它的递归定义如下: (1) 二项树B0只有一个结点: (2) 二项树Bk由两棵二项树B(k-1)组成的,其中一棵树是另一棵树根的最左孩子. 如下图所示: 上图的B0.B1.B2.B3.B4都是二项树.对比前面提到的二项树的定义:B0只有一个节点,B1由两个B0所组成,B2由两个B1所组成,B3由两个B2所组成,B4由两个B3所组成:而且,当两颗相同的二项树组成另一棵树时,其

数据结构——二项堆

二项树的介绍 二项树的定义 二项堆是二项树的集合.在了解二项堆之前,先对二项树进行介绍. 二项树是一种递归定义的有序树.它的递归定义如下:(01) 二项树B0只有一个结点:(02) 二项树Bk由两棵二项树B(k-1)组成的,其中一棵树是另一棵树根的最左孩子.如下图所示: 上图的B0.B1.B2.B3.B4都是二项树.对比前面提到的二项树的定义:B0只有一个节点,B1由两个B0所组成,B2由两个B1所组成,B3由两个B2所组成,B4由两个B3所组成:而且,当两颗相同的二项树组成另一棵树时,其中一棵

优先队列(堆)&#183;二项队列

目录 一. 定义 二. 结构 三. 操作 3.1. 合并 3.1. 删除最小值(deleteMin) 四. 二项队列的实现 代码地址 一. 定义 ? 我们知道,左式堆每次操作的时间界是\(O(logN)\).二项队列支持合并.插入.删除最小值,每次插入的平均时间为常数时间,而最坏时间是\(O(logN)\). ? 二项队列: 不是一棵堆序的树,而是堆序的树的集合,成为森林. 森林的每棵树都是二项树(binomial tree). 每个高度上至多存在一棵二项树. 二. 结构 ? 结构图解: ? 高

堆之二叉堆

堆的定义 堆通常是一个可以被看做一棵树,它满足下列性质: 堆中任意节点的值总是不大于(不小于)其子节点的值: 堆总是一棵完全树. 将任意节点不大于其子节点的堆叫做最小堆或小根堆,而将任意节点不小于其子节点的堆叫做最大堆或大根堆.常见的堆有二叉堆.左倾堆.斜堆.二项堆.斐波那契堆等等. 二叉堆 堆有两种性质:结构性和堆序性 结构性:堆是一颗完全二叉树.若设完全二叉树的高度是h,则它的节点数是2^h到2^(h+1) - 1:则节点数为N的完全二叉树的高度O(logn). 完全二叉树中父子节点位置关系