关于斐波那契堆的设计和分析的问题



事实证明,Fibonacci堆很难理解——尽管CLRS已经非常好的尝试让它了解它是如何工作的。但是有些问题我真的不清楚:

  • 你为什么要选择像t+2m这样的势函数?理由是什么
  • 标记节点背后的原因是什么?我认为根列表中的节点等,但你为什么要想出这样的方案

谢谢!

选择势函数的原因与不同因素的组合有关。通常,电势选择为t+2m,其中t是树的数量,m是标记节点的数量。我们可以分别分析这些片段。

首先,潜在函数包含一个t项,因为删除最小步骤是通过重复合并链表中的不同树来实现的。执行此操作所需的时间取决于树的数量,每次迭代都会将树的数量降到大约为O(logn)的数字,其中n是堆中的节点数量。通过使潜在函数包含一个t项,可以将折叠所有树所做的工作追溯到最初将树添加到此列表中的早期操作。

出于类似的原因,势函数包含了一个2m项。当我们调用reduce键时,我们从其父节点上剪切节点,然后标记父节点。如果父对象已经被标记,我们将其剪切,然后标记其父对象。当我们不断切割节点时,这里所做的工作量与我们所走路径的长度成正比,但随后它会取消标记所有涉及的节点。因此,如果我们有一个潜在的函数,将标记节点的数量考虑在内,那么我们可以说,虽然单个长序列的切割可能很昂贵,但这项工作可以追溯到早期的操作,并更均匀地分布。这个术语是2m而不是m的原因是,当我们通过减少被切割的节点数量来降低潜力时,我们也通过将更多的树添加回链表来增加t潜力。通过说标记节点中的每一个下降都会使电势下降两个,那么从一个切割开始的电势的净下降是-1,所以我们可以将未来的合并步骤计入这个下降。

至于我们为什么要做标记,这主要是为了在确定斐波那契堆中可以保留的树的数量和大小时,让数学正确计算出来。有人可以说,这是最初提出斐波那契堆所需要的真正天才的一步。从本质上讲,如果你能从每棵树中剪切太多的子树,那么堆就会失去平衡,如果你不能剪切足够多,那么你就不能有效地实现reduce-key。找到说"你可以失去一个孩子"的平衡是一个很好的折衷方案,并使最终的数学结果非常好。

希望这能有所帮助!

最新更新