📜  二项堆

📅  最后修改于: 2021-10-28 01:51:23             🧑  作者: Mango

二叉堆的主要应用是作为实现优先级队列。二项堆是二叉堆的扩展,它与二叉堆提供的其他操作一起提供更快的联合或合并操作。

二项式堆是二项式树的集合

什么是二叉树?
0 阶二叉树有 1 个节点。可以通过取两棵 k-1 阶二叉树并将其中一个作为最左边的孩子或其他来构建 k 阶二叉树。
k 阶二叉树具有以下特性。
a) 它正好有2k 个节点。
b) 它的深度为 k。
c) 对于 i = 0, 1, …,在深度 i 处正好有 k 个C i 节点。 . . ,k。
d) 根的度数为 k,根的子节点本身就是二叉树,从左到右的顺序为 k-1, k-2,.. 0。

k = 0 (Single Node)

 o

k = 1 (2 nodes) 
[We take two k = 0 order Binomial Trees, and
make one as child of other]
  o
 /  
o     

k = 2 (4 nodes)
[We take two k = 1 order Binomial Trees, and
make one as child of other]
     o
   /   \
  o     o
 /       
o        

k = 3 (8 nodes)
[We take two k = 2 order Binomial Trees, and
make one as child of other]
      o   
   /  | \ 
  o   o  o
 / \  | 
o   o o   
     \           
      o         

下图引用自 CLRS 书的第 2 版。

二叉树

二项式堆:
二项式堆是一组二项式树,其中每个二项式树都遵循最小堆属性。并且最多可以有一个任意度的二叉树。

二项式堆示例:

12------------10--------------------20
             /  \                 /  | \
           15    50             70  50  40
           |                  / |    |     
           30               80  85  65 
                            |
                           100
A Binomial Heap with 13 nodes. It is a collection of 3 
Binomial Trees of orders 0, 2 and 3 from left to right. 

    10--------------------20
   /  \                 /  | \
 15    50             70  50  40
 |                  / |    |     
 30               80  85  65 
                  |
                 100

具有 12 个节点的二项式堆。它是 2 个的集合
从左到右的 2 阶和 3 阶二叉树。

数字和二项式堆的二进制表示
具有 n 个节点的二项式堆的二项式树的数量等于 n 的二进制表示中设置的位数。例如,让 n 为 13,n (00001101) 的二进制表示中有 3 个设置位,因此有 3 个二叉树。我们还可以将这些二叉树的度与设置位的位置相关联。通过这种关系,我们可以得出结论,在具有“n”个节点的二项式堆中存在 O(Logn) 棵二项式树。

二项式堆的操作:
二项式堆中的主要操作是union(),其他所有操作都主要使用这个操作。 union() 操作是将两个二项式堆合并为一个。让我们先讨论其他操作,稍后我们将讨论联合。

  1. insert(H, k):向二项式堆“H”插入一个键“k”。此操作首先创建一个带有单个键 ‘k’ 的二项式堆,然后在 H 和新的二项式堆上调用 union。
  2. getMin(H):getMin() 的一种简单方法是遍历二叉树的根列表并返回最小键。此实现需要 O(Logn) 时间。它可以通过维护一个指向最小键根的指针优化为 O(1)。
  3. extractMin(H):这个操作也用到了 union()。我们首先调用 getMin() 来找到最小键二叉树,然后我们移除节点并通过连接移除的最小节点的所有子树来创建一个新的二项堆。最后,我们在 H 和新创建的二项式堆上调用 union()。此操作需要 O(Logn) 时间。
  4. delete(H):和二叉堆一样,delete操作首先将key减为负无穷大,然后调用extractMin()。
  5. reduceKey(H):decreaseKey() 也类似于二叉堆。我们将减少的键与其父项进行比较,如果父项的键更多,我们交换键并为父项重复。当我们到达一个其父节点具有较小键的节点或我们到达根节点时,我们就停止了。 reduceKey() 的时间复杂度是 O(Logn)。

    二项式堆中的联合操作:
    给定两个二项式堆 H1 和 H2, union(H1, H2) 创建一个二项式堆。

  6. 第一步是简单地按度数非递减顺序合并两个堆。在下图中,图(b)显示了合并后的结果。
  7. 在简单合并之后,我们需要确保最多有一个任意阶的二叉树。为此,我们需要组合相同顺序的二叉树。我们遍历合并根的列表,跟踪三指针,prev,x 和 next-x。当我们遍历根列表时,可能有以下 4 种情况。
    ——案例1:x和next-x的顺序不一样,我们直接往前走。
    在以下 3 种情况下,x 和 next-x 的顺序相同。
    ——案例2:如果next-next-x的顺序也一样,则继续。
    —-案例3:如果x的key小于等于next-x的key,则通过将next-x与x链接,使next-x成为x的子节点。
    —-案例4:如果x的key更大,则将x作为next的孩子。

    下图取自 CLRS 书的第 2 版。

二项式堆联合

如何表示二项式堆?
二项式堆是一组二项式树。二叉树必须以允许顺序访问所有兄弟的方式表示,从最左边的兄弟开始(我们需要这个 in 和 extractMin() 和 delete())。这个想法是将二叉树表示为最左边的孩子和右边兄弟的表示,即每个节点存储两个指针,一个指向最左边的孩子,另一个指向右边的兄弟。

二项式堆的实现

资料来源:
Clifford Stein、Thomas H. Cormen、Charles E. Leiserson、Ronald L.

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程。