sort heaps data python data-structures heap recursive-datastructures

heaps - ¿Qué uso para una implementación de max-heap en Python?



heapsort python (8)

Python incluye el módulo heapq para min-montones, pero necesito un montón máximo. ¿Qué debería usar para una implementación de max-heap en Python?


Permitiéndole elegir una cantidad arbitraria de los artículos más grandes o más pequeños

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]


He creado un envoltorio de heap que invierte los valores para crear un montón máximo, así como una clase contenedora para un montón mínimo para hacer que la biblioteca tenga más estilo OOP. Here está la esencia. Hay tres clases; Heap (clase abstracta), HeapMin y HeapMax.

Métodos:

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


Implementé una versión máxima de heapq y la envié a PyPI. (Cambio muy leve del código heapq del módulo CPython).

https://pypi.python.org/pypi/heapq_max/

https://github.com/he-zhe/heapq_max

Instalación

pip install heapq_max

Uso

tl; dr: lo mismo que el módulo heapq excepto que se agrega ''_max'' a todas las funciones.

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


La forma más fácil es invertir el valor de las claves y usar heapq. Por ejemplo, convierta 1000.0 en -1000.0 y 5.0 en -5.0.


La solución es negar sus valores cuando los almacena en el montón, o invertir su comparación de objetos de la siguiente manera:

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)

Ejemplo de un max-heap:

maxh = [] heapq.heappush(maxh,MaxHeapInt(x)) x = maxh[0].val # fetch max value x = heapq.heappop(maxh).val # pop max value

Pero debe recordar envolver y desenvolver sus valores, lo que requiere saber si se trata de un montón mínimo o máximo.

MinHeap, clases de MaxHeap

Agregar clases para objetos MinHeap y MaxHeap puede simplificar su código:

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

Ejemplo de uso:

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"


Multiplica los valores por -1, y ahí tienes. Todos los números más altos son ahora los más bajos y viceversa.

Solo recuerde que cuando hace saltar un elemento para multiplicarlo con -1 nuevamente, para obtener el valor original nuevamente.


Puedes usar

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 luego quieres abrir elementos, utiliza:

heapq.heappop(minheap) # pop from minheap heapq._heappop_max(maxheap) # pop from maxheap


Si está insertando claves que son comparables pero no similares a la int, podría anular los operadores de comparación en ellas (es decir, <= become> y> se convierte en <=). De lo contrario, puede anular heapq._sift en el módulo heapq (al final todo es código de Python).