【问题标题】:Deleting a node from the middle of a heap从堆中间删除一个节点
【发布时间】:2012-09-18 09:47:38
【问题描述】:

如果我们可以在恒定时间内找到堆中的元素,则可以在 O(lg n) 中从堆中间删除一个节点。假设堆的节点包含 id 作为其字段。现在如果我们提供 id,我们如何在 O(lg n) 时间内删除节点?

一种解决方案可以是我们可以在每个节点中都有一个位置的地址,我们在堆中维护节点的索引。该数组将按节点 ID 排序。不过,这需要维护额外的数组。有没有其他好的方法来达到同样的效果。

PS:我在实现 Djikstra 的最短路径算法时遇到了这个问题。

【问题讨论】:

    标签: algorithm data-structures heap dijkstra


    【解决方案1】:

    我也遇到过类似的问题,下面是我想出的:

    解决方案 1: 如果您对删除某些随机项的调用将有一个指向项的指针,您可以将您的个人数据项存储在堆外;使堆成为指向这些项目的指针;并让每个项目都包含其当前的堆数组索引。

    示例:堆包含指向键为 [2 10 5 11 12 6] 的项的指针。持有值 10 的项目有一个名为 ArrayIndex = 1 的字段(从 0 开始计数)。因此,如果我有一个指向第 10 项的指针并想要删除它,我只需查看它的 ArrayIndex 并在堆中使用它进行正常删除。 O(1) 找到堆位置,然后通常 O(log n) 通过递归 heapify 删除它。

    解决方案 2: 如果您只有要删除的项目的键字段,而不是其地址,请尝试此操作。切换到红黑树,将有效负载数据放入实际的树节点中。对于插入和删除,这也是 O( log n )。它还可以在 O( log n ) 中找到具有给定 key 的项目,这使得 delete-by-key 继续为 log n。

    在这些之间,解决方案 1 将需要在每次交换时不断更新 ArrayIndex 字段的开销。这也导致了一种奇怪的一次性数据结构,下一个代码维护者需要研究和理解。我认为解决方案 2 的速度差不多,并且具有易于理解的算法的优势。

    【讨论】:

      【解决方案2】:

      每个数据结构都在设计时考虑了某些操作。来自关于堆操作的维基百科

      堆通常执行的操作有: create-heap:创建一个空堆 find-max 或 find-min:分别找到最大堆的最大项或最小堆的最小项 delete-max 或 delete-min:分别删除最大或最小堆的根节点 increase-key 或 reduction-key:分别更新最大或最小堆内的键 插入:向堆中添加一个新键 合并 连接两个堆以形成一个有效的新堆,其中包含两者的所有元素。

      这意味着,对于您正在寻找的操作来说,堆并不是最好的数据结构。我建议您寻找更适合的数据结构(取决于您的要求)..

      【讨论】:

      • Dijsktra 算法需要从堆的中间删除。
      【解决方案3】:

      索引 (id, node) 可以单独维护在具有 O(1) 查找复杂度(平均)的哈希表中。总体复杂度仍然为 O(log n)。

      【讨论】:

      • 是的,这是解决方案之一。我认为不使用额外空间是不可能的。对吗?
      • 这种外部哈希码想法的一个问题是,在普通堆中,项目总是在 Heapify() 中移动,这需要每次交换都更新哈希表或删除/插入。这开始涉及大量哈希表更新,此时其他一些 log-n 插入、log-n 删除数据结构将更有意义。
      猜你喜欢
      • 2023-04-06
      • 2015-03-08
      • 2014-04-27
      • 2011-06-06
      • 2017-03-04
      • 2014-12-14
      • 2014-06-23
      相关资源
      最近更新 更多