Python には最小ヒープ用の heapq モジュールが含まれていますが、最大ヒープが必要です。Python での最大ヒープの実装には何を使用すればよいですか?
17 に答える
最も簡単な方法は、キーの値を反転して heapq を使用することです。たとえば、1000.0 を -1000.0 に、5.0 を -5.0 に変更します。
使用できます
import heapq
listForTree = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
heapq.heapify(listForTree) # for a min heap
heapq._heapify_max(listForTree) # for a maxheap!!
要素をポップしたい場合は、次を使用します。
heapq.heappop(minheap) # pop from minheap
heapq._heappop_max(maxheap) # pop from maxheap
解決策は、値をヒープに格納するときに値を無効にするか、次のようにオブジェクト比較を反転することです。
import heapq
class MaxHeapObj(object):
def __init__(self, val): self.val = val
def __lt__(self, other): return self.val > other.val
def __eq__(self, other): return self.val == other.val
def __str__(self): return str(self.val)
最大ヒープの例:
maxh = []
heapq.heappush(maxh, MaxHeapObj(x))
x = maxh[0].val # fetch max value
x = heapq.heappop(maxh).val # pop max value
ただし、値をラップおよびアンラップすることを忘れないでください。これには、最小ヒープまたは最大ヒープのどちらを扱っているかを知る必要があります。
MinHeap、MaxHeap クラス
MinHeap
およびオブジェクトのクラスを追加するとMaxHeap
、コードを簡素化できます。
class MinHeap(object):
def __init__(self): self.h = []
def heappush(self, x): heapq.heappush(self.h, x)
def heappop(self): return heapq.heappop(self.h)
def __getitem__(self, i): return self.h[i]
def __len__(self): return len(self.h)
class MaxHeap(MinHeap):
def heappush(self, x): heapq.heappush(self.h, MaxHeapObj(x))
def heappop(self): return heapq.heappop(self.h).val
def __getitem__(self, i): return self.h[i].val
使用例:
minh = MinHeap()
maxh = MaxHeap()
# add some values
minh.heappush(12)
maxh.heappush(12)
minh.heappush(4)
maxh.heappush(4)
# fetch "top" values
print(minh[0], maxh[0]) # "4 12"
# fetch and remove "top" values
print(minh.heappop(), maxh.heappop()) # "4 12"
heapq の最大ヒープ バージョンを実装し、PyPI に提出しました。(heapq モジュール CPython コードのごくわずかな変更。)
https://pypi.python.org/pypi/heapq_max/
https://github.com/he-zhe/heapq_max
インストール
pip install heapq_max
使用法
tl;dr: すべての関数に '_max' を追加する以外は、heapq モジュールと同じです。
heap_max = [] # creates an empty heap
heappush_max(heap_max, item) # pushes a new item on the heap
item = heappop_max(heap_max) # pops the largest item from the heap
item = heap_max[0] # largest item on the heap without popping it
heapify_max(x) # transforms list into a heap, in-place, in linear time
item = heapreplace_max(heap_max, item) # pops and returns largest item, and
# adds new item; the heap size is unchanged
これは、MaxHeap
に基づく単純な実装ですheapq
。数値でのみ機能しますが。
import heapq
from typing import List
class MaxHeap:
def __init__(self):
self.data = []
def top(self):
return -self.data[0]
def push(self, val):
heapq.heappush(self.data, -val)
def pop(self):
return -heapq.heappop(self.data)
使用法:
max_heap = MaxHeap()
max_heap.push(3)
max_heap.push(5)
max_heap.push(1)
print(max_heap.top()) # 5
比較可能であるが int に似ていないキーを挿入する場合、それらの比較演算子を上書きする可能性があります (つまり、<= になる > および > になる <=)。それ以外の場合は、heapq モジュールで heapq._siftup をオーバーライドできます (最終的にはすべて単なる Python コードです)。
値を反転して最大ヒープを作成するヒープ ラッパーと、ライブラリをより OOP 風にする最小ヒープのラッパー クラスを作成しました。これが要点です。3 つのクラスがあります。Heap (抽象クラス)、HeapMin、および HeapMax。
方法:
isempty() -> bool; obvious
getroot() -> int; returns min/max
push() -> None; equivalent to heapq.heappush
pop() -> int; equivalent to heapq.heappop
view_min()/view_max() -> int; alias for getroot()
pushpop() -> int; equivalent to heapq.pushpop
Isaac Turner の優れた回答に続いて、最大ヒープを使用してオリジンに最も近い K 個のポイントに基づく例を挙げたいと思います。
from math import sqrt
import heapq
class MaxHeapObj(object):
def __init__(self, val):
self.val = val.distance
self.coordinates = val.coordinates
def __lt__(self, other):
return self.val > other.val
def __eq__(self, other):
return self.val == other.val
def __str__(self):
return str(self.val)
class MinHeap(object):
def __init__(self):
self.h = []
def heappush(self, x):
heapq.heappush(self.h, x)
def heappop(self):
return heapq.heappop(self.h)
def __getitem__(self, i):
return self.h[i]
def __len__(self):
return len(self.h)
class MaxHeap(MinHeap):
def heappush(self, x):
heapq.heappush(self.h, MaxHeapObj(x))
def heappop(self):
return heapq.heappop(self.h).val
def peek(self):
return heapq.nsmallest(1, self.h)[0].val
def __getitem__(self, i):
return self.h[i].val
class Point():
def __init__(self, x, y):
self.distance = round(sqrt(x**2 + y**2), 3)
self.coordinates = (x, y)
def find_k_closest(points, k):
res = [Point(x, y) for (x, y) in points]
maxh = MaxHeap()
for i in range(k):
maxh.heappush(res[i])
for p in res[k:]:
if p.distance < maxh.peek():
maxh.heappop()
maxh.heappush(p)
res = [str(x.coordinates) for x in maxh.h]
print(f"{k} closest points from origin : {', '.join(res)}")
points = [(10, 8), (-2, 4), (0, -2), (-1, 0), (3, 5), (-2, 3), (3, 2), (0, 1)]
find_k_closest(points, 3)