【问题标题】:delete arbitrary item from heap in python从python中的堆中删除任意项
【发布时间】:2018-08-13 08:19:13
【问题描述】:

是否有二进制堆实现,我可以在 log n 时间弹出除根以外的其他元素?

我使用 heapq - 但heap.index( wKeys ) in

heap.pop( heap.index( wKeys ) )

很慢。我需要一个二进制堆来解决我的问题 - 我有时会使用

heapq.heappop(heap)

但还需要从堆顶部弹出其他元素。所以像 heapq 实现这样的二进制堆应该可以做到这一点,但我没有找到二进制搜索方法。我还查看了treap (http://stromberg.dnsalias.org/~strombrg/treap/),在这里也找不到这样的方法。

【问题讨论】:

  • heapq 文档 (docs.python.org/3.5/library/heapq.html) 似乎根本没有提到索引方法。您在wKeys 中传递了多少个密钥?一般来说,我不希望找到特定成员的索引会很快 - 尽管我的 comp sci 相当生疏。 Ref docs.python.org/3.5/library/… 似乎是“你如何找到 [an item] 并将其从队列中删除?”是一个悬而未决的问题,尽管它提出了一个解决方案。我认为通常你想要做的不是二进制堆的“内置”属性。
  • 二叉树只是意味着每个节点最多有2个孩子。二叉树本身在节点上没有先天的“排序”。碰巧二叉树的一个常见用途是允许高效二叉搜索的有序二叉树。 treap 可能有一些额外的实现(例如“插件”字典),可以提高查找效率,但这将出现在推送/弹出的额外操作和额外存储成本的代码中。
  • @EndreMoen:二叉堆被组织成二叉树,而不是二叉搜索树。在二叉堆中查找项目需要顺序搜索。
  • 从二进制堆中删除任意元素是一个 O(log n) 操作,如stackoverflow.com/a/8706363/56778 中所述。 查找任意元素是一个 O(n) 操作,除非您将堆与诸如哈希映射或字典之类的查找机制结合起来,以跟踪每个项目在堆中的位置。
  • 您需要修改堆代码,使其包含一个字典,该字典以项键为键,项在堆中的索引为值。在移动项目的代码中,每次在堆中移动项目时,都必须更新项目在字典中的位置。在 python 中可能有这样做的例子。如果不是,这不是一个困难的修改。

标签: python data-structures heap binary-heap


【解决方案1】:
class RemoveHeap:
    def __init__(self):
        self.h = []
        self.track = collections.defaultdict(collections.deque)
        self.counter = itertools.count()

    def insert_item(self, val):
        count = next(self.counter)
        item = [val, count, 'active']
        self.track[val].append(item)
        heapq.heappush(self.h, item)

    def delete_item(self, val):
        if val in self.track:
            items = self.track[val]
            for item in items:
                if item[2] == 'active':
                    item[2] = 'deleted'
                    break

    def pop_item(self):
        while len(self.h) > 0:
            item = heapq.heappop(self.h)
            item_track = self.track[item[0]]
            item_track.popleft()
            if len(item_track) == 0:
                del self.track[item[0]]
            else:
                self.track[item[0]] = item_track
            if item[2] == 'active':
                return item[0]

    def peek_item(self):
        item = self.h[0]
        if item[2] == 'deleted':
            x = self.pop_item()
            self.insert_item(x)
            return x
        return item[0]

【讨论】:

  • 你试过我在下面的回答中链接到的 heapq_with_index 吗?
【解决方案2】:

我修改了 heapq 的实现,向heappop() 和heappush() 添加了一个参数——即heapIndex。这需要{item: index} 的字典并在heapIndex 弹出或推入heap 时更新它。

我还添加了一个新方法heappop_arbitrary(),它删除任意元素并更新heapIndex

代码可在此处获得:https://github.com/emoen/heapq_with_index

我已将方法 heappop(),heappush() 重命名为 heappop2(), heappush2() 以避免与原始方法混淆。

我还没有为 heapq 中可用的任何其他功能实现此功能。

编辑:如果你可以使用 repo,请加注星标 :)

【讨论】:

  • 添加了 changeValue()
  • heappop_arbitrary() 和 changeValue() 仍然很慢。
  • heappop_arbitrary() 和 changeValue() 不应该很慢。它们应该比 heappop2() 更快。此外,您应该能够在heappop_arbitrary' to remove the last item from the heap and then call changeValue()`中重新编码您的else:(最后一个)。
猜你喜欢
  • 2012-09-16
  • 2012-03-06
  • 2012-04-27
  • 2021-02-20
  • 2014-05-24
  • 2017-11-26
  • 2010-10-17
  • 2016-04-22
  • 1970-01-01
相关资源
最近更新 更多