Python inclut le module heapq pour min-heaps, mais j'ai besoin d'un tas max. Que dois-je utiliser pour une implémentation max-heap en Python?
Le moyen le plus simple consiste à inverser la valeur des clés et à utiliser heapq. Par exemple, convertissez 1000.0 en -1000.0 et 5.0 en -5.0.
Vous pouvez utiliser
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!!
Si vous voulez ensuite faire apparaître des éléments, utilisez:
heapq.heappop(minheap) # pop from minheap
heapq._heappop_max(maxheap) # pop from maxheap
La solution consiste à annuler vos valeurs lorsque vous les stockez dans le tas, ou à inverser votre comparaison d'objet de la manière suivante:
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)
Exemple de max-tas:
maxh = []
heapq.heappush(maxh,MaxHeapInt(x))
x = maxh[0].val # fetch max value
x = heapq.heappop(maxh).val # pop max value
Mais vous devez vous rappeler d’envelopper et de dérouler vos valeurs, ce qui nécessite de savoir si vous avez affaire à un minimum ou un maximum.
L'ajout de classes pour les objets MinHeap
et MaxHeap
peut simplifier votre code:
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
Exemple d'utilisation:
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"
Multipliez les valeurs par -1, et voilà. Tous les nombres les plus élevés sont maintenant les plus bas et vice versa.
Rappelez-vous simplement que lorsque vous dépassez un élément, multipliez-le par -1, afin de récupérer la valeur d'origine.
Si vous insérez des clés comparables mais pas de type int, vous pouvez éventuellement remplacer les opérateurs de comparaison sur ces dernières (c'est-à-dire <= devenir> et> devient <=). Sinon, vous pouvez remplacer heapq._siftup dans le module heapq (il ne s'agit que de code Python, à la fin).
import heapq
heap = [23, 7, -4, 18, 23, 42, 37, 2, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
heapq.heapify(heap)
print(heapq.nlargest(3, heap)) # [42, 42, 37]
print(heapq.nsmallest(3, heap)) # [-4, -4, 2]
J'ai implémenté une version max heap de heapq et l'ai soumise à PyPI. (Très léger changement du code CPython du module heapq.)
https://pypi.python.org/pypi/heapq_max/
https://github.com/he-zhe/heapq_max
Installation
pip install heapq_max
Usage
tl; dr: idem module heapq sauf que "_max" est ajouté à toutes les fonctions.
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
Étendre la classe int et remplacer_LT_est l’un des moyens.
import queue
class MyInt(int):
def __lt__(self, other):
return self > other
def main():
q = queue.PriorityQueue()
q.put(MyInt(10))
q.put(MyInt(5))
q.put(MyInt(1))
while not q.empty():
print (q.get())
if __== "__main__":
main()
J'ai créé un wrapper de tas qui inverse les valeurs pour créer un tas max, ainsi qu'une classe wrapper pour un tas min afin de rendre la bibliothèque plus semblable à la POO. Ici est le Gist. Il y a trois classes; Heap (classe abstraite), HeapMin et HeapMax.
Les méthodes:
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