我正在尝试使用自定义排序谓词构建堆。由于进入它的值是'用户定义'类型,我无法修改它们的内置比较谓词。
有没有办法做类似的事情:
h = heapq.heapify([...], key=my_lt_pred)
h = heapq.heappush(h, key=my_lt_pred)
或者甚至更好,我可以将heapq函数包装在我自己的容器中,这样我就不需要继续传递谓词了。
答案 0 :(得分:81)
根据heapq documentation,自定义堆顺序的方法是让堆上的每个元素都是元组,第一个元组元素是接受普通Python比较的元素。
heapq模块中的函数有点麻烦(因为它们不是面向对象的),并且总是要求我们的堆对象(堆化列表)作为第一个参数显式传递。我们可以通过创建一个非常简单的包装类来一举两得,它将允许我们指定一个key
函数,并将堆作为对象呈现。
下面的类保留了一个内部列表,其中每个元素都是一个元组,其中第一个成员是一个键,使用key
参数在元素插入时计算,在Heap实例化时传递:
# -*- coding: utf-8 -*-
import heapq
class MyHeap(object):
def __init__(self, initial=None, key=lambda x:x):
self.key = key
if initial:
self._data = [(key(item), item) for item in initial]
heapq.heapify(self._data)
else:
self._data = []
def push(self, item):
heapq.heappush(self._data, (self.key(item), item))
def pop(self):
return heapq.heappop(self._data)[1]
答案 1 :(得分:41)
定义一个类,在其中重写__lt__()
函数。请参见下面的示例(适用于Python 3.7):
import heapq
class Node(object):
def __init__(self, val: int):
self.val = val
def __repr__(self):
return f'Node value: {self.val}'
def __lt__(self, other):
return self.val < other.val
heap = [Node(2), Node(0), Node(1), Node(4), Node(2)]
heapq.heapify(heap)
print(heap) # output: [Node value: 0, Node value: 2, Node value: 1, Node value: 4, Node value: 2]
heapq.heappop(heap)
print(heap) # output: [Node value: 1, Node value: 2, Node value: 2, Node value: 4]
答案 2 :(得分:10)
heapq documentation表明堆元素可以是元组,其中第一个元素是优先级并定义排序顺序。
然而,与您的问题更相关的是,文档包含discussion with sample code如何实现自己的heapq包装函数来处理排序稳定性问题和具有相同优先级的元素(以及其他问题)
简而言之,他们的解决方案是让heapq中的每个元素都是具有优先级的三元组,一个条目计数和要插入的元素。条目计数确保具有相同优先级的元素按照它们添加到heapq的顺序排序。
答案 3 :(得分:1)
这两个答案的限制是他们不允许将关系视为关系。在第一种情况下,通过比较项目来打破联系,在第二种情况下通过比较输入顺序来打破让关系成为关系更快,如果有很多关系,它可以产生很大的不同。基于上述内容和文档,目前尚不清楚这是否可以在heapq中实现。看起来很奇怪heapq不接受密钥,而在同一模块中从它派生的函数也是如此 P.S: 如果你按照第一条评论中的链接(&#34;可能重复......&#34;),还有另一个定义le的建议,这似乎是一个解决方案。
答案 4 :(得分:1)
orderDetails
使用它比较堆q中对象的值