web-dev-qa-db-fra.com

Que dois-je utiliser pour une implémentation max-heap en Python?

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?

146
Douglas Mayle

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.

146
Daniel Stutzbach

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
139
Lijo Joseph

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. 

MinHeap, classes MaxHeap

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"
38
Isaac Turner

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.

8

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).

4
rlotun

Vous permettant de choisir une quantité arbitraire d'éléments les plus grands ou les plus petits

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]
2
jasonleonhard

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
1
Zhe He

É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()
0
Gaurav

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
0