Algorithm 为什么配对堆在删除_min时需要特殊的两次传递?
我正在看报纸 这很简单,唯一棘手的部分是Algorithm 为什么配对堆在删除_min时需要特殊的两次传递?,algorithm,data-structures,pairing-heap,Algorithm,Data Structures,Pairing Heap,我正在看报纸 这很简单,唯一棘手的部分是delete\u min操作 唯一非平凡的基本操作是删除 堆中的最小元素。标准策略首先合并 成对的子标题(这是赋予此数据结构 名称),然后合并生成的堆列表 从右到左: 我不认为我需要在这里复制/粘贴代码,因为它位于wiki链接中 我的问题是 他们为什么要进行两次合并 为什么他们第一次合并配对?不直接将它们全部合并 为什么在合并对之后,要从右向左合并 对于配对堆,将项添加到堆是一个O(1)操作,因为它所做的只是将节点添加为新根(如果它小于当前根),或者作为当
delete\u min
操作
唯一非平凡的基本操作是删除
堆中的最小元素。标准策略首先合并
成对的子标题(这是赋予此数据结构
名称),然后合并生成的堆列表
从右到左:
我不认为我需要在这里复制/粘贴代码,因为它位于wiki链接中
我的问题是
对于配对堆,将项添加到堆是一个O(1)操作,因为它所做的只是将节点添加为新根(如果它小于当前根),或者作为当前根的第一个子节点。因此,如果您创建了一个配对堆,并将数字0到9依次添加到该堆中,您将得到:
0
|
-----------------
| | | | | | | | |
9 8 7 6 5 4 3 2 1
如果然后执行delete min,则必须查看每个子项以确定最小项并构建新堆。如果使用从左到右的朴素组合方法,则会得到以下树:
1
|
---------------
| | | | | | | |
9 8 7 6 5 4 3 2
下次执行delete min时,您必须查看剩余的8个子项等。使用此技术,创建并从堆中删除所有项将是一个O(n^2)操作
成对组合的两次传递方法,然后组合成对的结果是更有效的结构。考虑第一种情况。删除最小项后,我们剩下9个孩子。它们从左到右成对组合,产生:
8 6 4 2 1
/ / / /
9 7 5 3
然后我们从右到左组合这些对。分步骤:
8 6 4 1
/ / / /
9 7 5 2
/
3
8 6 1
/ / / \
9 7 2 4
/ /
3 5
8 1
/ |
9 ---------
6 4 2
/ / /
7 5 3
1
|
----------
8 6 4 2
/ / / /
9 7 5 3
现在,下一次调用delete min时,只有四个节点需要检查,下一次之后将只有两个节点需要检查。使用两次组合方法可将子级的节点数减少至少一半。我的安排是最糟糕的。如果项目按升序排列,则第一个delete min操作将生成一个在根下只有两个子节点的树
这是配对堆的摊销复杂性的一个特别好的例子。insert是O(1),但是一系列insert操作之后的第一个delete min是O(n),其中n
是自上次delete-min以来插入的项目数。两次组合规则的优点在于它可以快速重新组织堆以降低O(n)的复杂性
根据该组合规则,delete min的摊销复杂度为O(logn)。根据严格的从左到右规则,它是O(n)。原稿对此进行了很好的解释。为什么第二阶段是从右到左很重要?在我看来,它完全等同于从左到右的插入顺序,无论方向如何,插入顺序都可以生成相同的树结构。在您的示例中,这将产生一个基本上向左不平衡的二叉树。@Celelibi:最有可能的是,相反的顺序是组合过程递归性质的结果。提到了从左到右进行两次传递的可能性,但没有说明性能。如果使用左子级、右同级链表将堆表示为树,则第一次传递时从左到右更容易。如果您使用中间列表或队列来保存第一次传递的结果,那么第二次传递可以按任意顺序进行,但我猜从右到左可以消除结果树中的偏差,并使结果趋于均匀。@Paulchenchronch:经过一点试验,在第二次传球时,我看不到左-左与左-右在表现上有任何差异。我敢肯定,在最初的论文中描述的左右是他们对问题的递归定义的产物。基本上,它们只是在展开堆栈的同时进行合并。我转向了迭代实现,因为当您有一个大堆时,递归实现会破坏堆栈。正如你所说,左孩子右兄弟姐妹表示法使两个从左到右的过程更可取。构建一个表现出类似最坏情况行为的树不是很容易吗?还是我错过了第一关的重要内容?