我正在尝试使用自定义排序谓词构建堆。由于输入的值属于“用户定义”类型,因此我无法修改其内置比较谓词。
有没有办法做类似的事情:
h = heapq.heapify([...], key=my_lt_pred)
h = heapq.heappush(h, key=my_lt_pred)
甚至更好的是,我可以将heapq函数包装在自己的容器中,这样就不需要继续传递谓词。
我正在尝试使用自定义排序谓词构建堆。由于输入的值属于“用户定义”类型,因此我无法修改其内置比较谓词。
有没有办法做类似的事情:
h = heapq.heapify([...], key=my_lt_pred)
h = heapq.heappush(h, key=my_lt_pred)
甚至更好的是,我可以将heapq函数包装在自己的容器中,这样就不需要继续传递谓词。
Answers:
根据heapq文档,自定义堆顺序的方法是使堆上的每个元素成为一个元组,第一个tuple元素是一个接受常规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
self.index = 0
if initial:
self._data = [(key(item), i, item) for i, item in enumerate(initial)]
self.index = len(self._data)
heapq.heapify(self._data)
else:
self._data = []
def push(self, item):
heapq.heappush(self._data, (self.key(item), self.index, item))
self.index += 1
def pop(self):
return heapq.heappop(self._data)[2]
(额外的self.index
部分是避免当评估的键值是平局并且存储的值不能直接比较时发生冲突-否则heapq可能因TypeError失败)
id(item)
打破联系作为元组的中间元素。
定义一个类,在其中重写__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]
__gt__
改为使用此工具进行了测试,并且效果很好。为什么使用哪种魔术方法都没有关系?我在heapq
的文档中找不到任何内容。也许与Python一般如何进行比较有关?
heapq
,Python__lt__()
首先查找。如果未定义,它将寻找__gt__()
。如果都未定义,则抛出TypeError: '<' not supported between instances of 'Node' and 'Node'
。可以通过定义__lt__()
和并__gt__()
在每个语句中放置一个打印语句并具有__lt__()
return来确认这一点NotImplemented
。
setattr(ListNode, "__lt__", lambda self, other: self.val <= other.val)
用它来比较heapq中对象的值