如果我们可以在常量时间内找到堆中的元素,则可以在O(lg n)中完成从堆中间删除节点。假设堆的节点包含id作为其字段。现在,如果我们提供id,我们如何在O(lg n)时间内删除节点?
一个解决方案可以是我们可以在每个节点中拥有一个位置的地址,其中我们维护堆中节点的索引。该数组将按节点ID排序。这需要维护额外的阵列。有没有其他好的方法来实现同样的目标。
PS:我在实现Djikstra的最短路径算法时遇到了这个问题。
答案 0 :(得分:1)
索引(id,node)可以在哈希表中单独维护,该哈希表具有O(1)查找复杂度(平均)。然后整体复杂性仍为O(log n)。
答案 1 :(得分:0)
每个数据结构的设计都考虑到了某些操作。来自维基百科关于堆操作
The operations commonly performed with a heap are: create-heap: create an empty heap find-max or find-min: find the maximum item of a max-heap or a minimum item of a min-heap, respectively delete-max or delete-min: removing the root node of a max- or min-heap, respectively increase-key or decrease-key: updating a key within a max- or min-heap, respectively insert: adding a new key to the heap merge joining two heaps to form a valid new heap containing all the elements of both.
这意味着,堆不是您正在寻找的操作的最佳数据结构。我建议你寻找一个更合适的数据结构(取决于你的要求)..
答案 2 :(得分:0)
我遇到了类似的问题,这是我想出的:
解决方案1::如果删除某个随机项目的调用将具有指向该项目的指针,则可以将各个数据项目存储在堆之外;使堆成为这些项目的 pointers 指针;并让每个项目都包含其当前的堆数组索引。
示例:堆包含指向带有键[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)中找到具有给定键的项,这使得按键删除继续为log n。
在这些方法之间,解决方案1将需要每次交换都不断更新ArrayIndex字段的开销。它还导致一种奇怪的一次性数据结构,下一个代码维护者需要研究和理解。我认为解决方案2的速度差不多,并且具有的优点是它是一种易于理解的算法。