El módulo heapq (clasificación de montón) en python3 utiliza

1. Introducción a heapq

heapq - Algoritmo de clasificación de montón: heapq implementa un algoritmo de clasificación de montón mínimo adecuado para usar con las listas de Python.

1. Árbol binario

Cada nodo en el árbol tiene como máximo dos hijos:
heapq

2. Árbol binario completo

Además de los nodos de hoja en el árbol, cada nodo tiene dos nodos secundarios:
heapq

3. Árbol binario completo

Si el árbol binario, excepto la última capa de nodos, es un árbol binario completo, y los nodos de la última capa se distribuyen de izquierda a derecha, entonces este árbol binario se denomina árbol binario completo.
heapq

4. montón

Un montón es una estructura de datos que es un árbol binario completo . El montón mínimo agrega nuevas reglas sobre la base del montón. El valor de su nodo raíz es el más pequeño, y el valor del nodo principal de cualquier nodo es menor o igual que el valor de sus nodos izquierdo y derecho . Dado que un montón binario se puede representar mediante listas o matrices organizadas, los elementos secundarios del elemento N se encuentran en las posiciones 2*N+1 y 2*N+2. Este diseño permite reorganizar el montón para que no sea necesario reasignar tanta memoria cuando se agregan o eliminan elementos.
Distinga entre el montón y la pila: el montón está relacionado con el árbol binario, como un montón de arena en forma de pirámide; y la pila es como un bote de basura en posición vertical, una columna hacia abajo.

5. Montón máximo

Un montón máximo garantiza que un nodo principal sea mayor o igual que sus dos hijos.

6. Montón mínimo

Un montón mínimo requiere que un nodo principal sea menor o igual que sus nodos secundarios. El módulo heapq de Python implementa un min-heap.
heapq

7. Resumen

Un montón es un árbol binario representado por una matriz. Se divide en un montón raíz grande y un montón raíz pequeño. El montón raíz grande es el montón con el elemento más grande en la parte superior del montón, y el montón raíz pequeño es el montón. montón con el elemento más pequeño en la parte superior del montón.
heapq

2. Uso

1. heappush(heap, item) crea montones raíz grandes y pequeños

heapq.heappush() es para agregar un nuevo valor al montón. En este momento, se establece automáticamente un pequeño montón raíz. El código es el siguiente:

import heapq
a = []   #创建一个空堆
heapq.heappush(a,18)
heapq.heappush(a,1)
heapq.heappush(a,20)
heapq.heappush(a,10)
heapq.heappush(a,5)
heapq.heappush(a,200)
print(a)

producción:

[1, 5, 20, 18, 10, 200]

Sin embargo, heapq no proporciona directamente un método para construir un montón raíz grande. Se puede adoptar el siguiente método: agregue un signo negativo al elemento cada vez que presione (es decir, tome el número opuesto), y en este momento el mínimo El valor se convierte en el valor máximo, y viceversa. Luego, el valor real El valor máximo puede estar en la parte superior del montón, y puede ser negativo al devolver .

a = []
for i in [1, 5, 20, 18, 10, 200]:
    heapq.heappush(a,-i)
print(list(map(lambda x:-x,a)))

producción:

[200, 18, 20, 1, 10, 5]

2. heapify(heap) crea montones raíz grandes y pequeños

heapq.heapfiy() convierte una lista en un pequeño montón raíz en tiempo lineal (complejidad O(logn)):

a = [1, 5, 20, 18, 10, 200]
heapq.heapify(a)
print(a)

producción:

[1, 5, 20, 18, 10, 200]

Use el mismo método anterior para crear un montón raíz grande:

a = [1, 5, 20, 18, 10, 200]
a = list(map(lambda x:-x,a))
heapq.heapify(a)
print([-x for x in a])

producción:

[200, 18, 20, 5, 10, 1]

En comparación con el montón raíz grande obtenido anteriormente, aunque el orden de los elementos en la tercera capa del árbol binario es diferente, todos se ajustan a la definición del montón raíz grande:

3. heappop(montón)

Usa heappop() para abrir y devolver el elemento más pequeño del montón, dejando el montón sin cambios. Genera IndexError si el montón está vacío.
heapq.heappop() aparece del montón y devuelve el valor más pequeño

3.1 Uso de heappop para ordenar montones

Por supuesto, la clasificación de montones también necesita usar heappush o heapify. Puede consultar la clasificación de montones en el resumen de algoritmos de clasificación. Aquí solo se publica el código:

import heapq
def heap_sort(arr):
    if not arr:
        return []
    h = []  #建立空堆
    for i in arr:
        heapq.heappush(h,i) #heappush自动建立小根堆
    return [heapq.heappop(h) for i in range(len(h))]  #heappop每次删除并返回列表中最小的值

Si se organiza de mayor a menor, hay dos métodos:
1) Crear primero una pila raíz pequeña y luego cada vez heappop(), en este momento obtener la disposición de menor a mayor y luego invertir.
2) Use el número opuesto para construir un montón raíz grande y luego heappop(-element). es decir, empujar (-elemento), pop (-elemento)

3.2 heappop() de lista ordinaria

Para una lista normal (es decir, una lista sin operaciones como heapify), la operación heappop en ella no mostrará el valor más pequeño de la lista, sino el primer valor:

>>> a=[3,6,1]
>>> heapify(a)                  #将a变成堆之后,可以对其操作
>>> heappop(a)
1
>>> b=[4,2,5]                   #b不是堆,如果对其进行操作,显示结果如下
>>> heappop(b)                  #按照顺序,删除第一个数值并返回,不会从中挑选出最小的
4
>>> heapify(b)                  #变成堆之后,再操作
>>> heappop(b)
2

4. heappushpop(montón,elemento)

heapq.heappushpop() es una combinación de heappush y heappop, y completa las funciones de ambos al mismo tiempo, primero ejecuta heappush() y luego realiza heappop()

>>>h =  heapq.heapify([1, 2, 9, 5])
>>> heappop(h)
1
>>> heappushpop(h,4)            #增加4同时删除最小值2并返回该最小值,与下列操作等同:
2                              
>>> h
[4, 5, 9]

Aparece 5 heapreplace(heap, item) y devuelve el elemento más pequeño del montón, y empuja un nuevo elemento al mismo tiempo

heapq.heapreplace() es lo opuesto a heapq.heappushpop(), primero ejecuta heappop() y luego heappush().

El tamaño del montón no cambia. Genera IndexError si el montón está vacío. Esta operación de un solo paso es más eficiente que hacer heappop() + heappush() secuencialmente, y es más apropiada cuando se usa un montón de tamaño fijo .
La combinación pop/push siempre devuelve un elemento del montón y lo reemplaza con item. El valor devuelto puede ser mayor que el artículo agregado. Si no desea esto, considere usar heappushpop() en su lugar. Su combinación push/pop devuelve el menor de los dos valores, dejando el valor mayor en el montón .

>>> a=[]
>>> heapreplace(a,3)            #如果list空,则报错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: index out of range
>>> heappush(a,3)
>>> a
[3]
>>> heapreplace(a,2)            #先执行删除(heappop(a)->3),再执行加入(heappush(a,2))
3
>>> a
[2]
>>> heappush(a,5)  
>>> heappush(a,9)
>>> heappush(a,4)
>>> a
[2, 4, 9, 5]
>>> heapreplace(a,6)            #先从堆a中找出最小值并返回,然后加入6
2
>>> a
[4, 5, 9, 6]
>>> heapreplace(a,1)            #1是后来加入的,在1加入之前,a中的最小值是4
4
>>> a
[1, 5, 9, 6]

6 combinar(*iterables)

heapq.merge() fusiona varios montones y los genera.
La lista de entrada está desordenada, y está desordenada después de la fusión. Si la lista de entrada está ordenada, también se ordena después de la fusión.heapq

7. nlargest(n , iterbale, key=Ninguno) 和 nsmallest(n , iterbale, key=Ninguno)

Obtenga los valores más grandes y más pequeños de la lista. La función de la tecla es similar a la tecla en el método sorted():

>>>a = [0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
>>>heapq.nlargest(5,a)
[25, 20, 15, 10, 8]

>>>b = [('a',1),('b',2),('c',3),('d',4),('e',5)]
>>>heapq.nlargest(1,b,key=lambda x:x[1])
[('e', 5)]

8. Análisis de complejidad

8.1 Complejidad de cada método

1) heapq.heapify(x): O(n)
2) heapq.heappush(heap, item): O(logn)
3) heapq.heappop(heap): O(logn)
Es decir, al insertar o eliminar elementos, todos los nodos Ajuste automático para garantizar que la complejidad de la estructura del montón sea O(log n)
4) heapq.nlargest(k,iterable) and heapq.nsmallest(k,iterable): O(n * log(t))

8.2 Comparación de la velocidad de cada método al clasificar y tomar TopN

Cuando se trata de clasificar y tomar los valores Top N, qué método es el más rápido de usar, el libro de cocina de python3 brinda muy buenos consejos:

1) Cuando el número de elementos a buscar es relativamente pequeño, utilice las funciones nlargest() y nsmallest() .
2) Si solo desea encontrar el único elemento mínimo o máximo (N = 1), use las funciones min() y max() .
3) Si el tamaño de N está cerca del tamaño de la colección, generalmente es más rápido ordenar la colección primero y luego usar la operación de división (ordenados (elementos) [: N] o ordenados (elementos) [-N:] ) .

9. Usar el módulo heapq para implementar una cola de prioridad

# priority 优先级

class PriorityQueue:
    def __init__(self):
        self._queue = []
        self._index = 0
    def push(self, item, priority):
        # heappush 在队列 _queue 上插入第一个元素
        heapq.heappush(self._queue, (-priority, self._index, item))
        self._index += 1
    def pop(self):
        # heappop 在队列 _queue 上删除第一个元素
        return heapq.heappop(self._queue)[-1]

class Item:
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return ‘Item({
    
    !r})’.format(self.name)

1) Llame al método push() para convertir la lista en datos de montón

2) Se inserta una tupla, y la comparación del tamaño de la tupla comienza desde el primer elemento, y el primer elemento es el mismo, y luego compara el segundo elemento. El esquema que adoptamos aquí es que si la prioridad es la misma, entonces de acuerdo con el segundo elemento, quien inserte primero en el montón tendrá un índice más pequeño, luego su valor será más pequeño

3) Obtenido por el método heapq.heappop(), este método mostrará primero el primer elemento y luego reemplazará el elemento emergente con el siguiente elemento más pequeño.

prueba:

q = PriorityQueue()

q.push(Item(‘foo’), 1)

q.push(Item(‘bar’), 5)

q.push(Item(‘spam’), 4)

q.push(Item(‘grok’), 1)

print(q.pop())

print(q.pop())

print(q.pop())

producción:

Item(‘bar’)

Item(‘spam’)

Item(‘foo’)

10. Impresión de salida de pila

import math
from io import StringIO

def show_tree(tree, total_width=36, fill=' '):
    """Pretty-print a tree."""
    output = StringIO()
    last_row = -1
    for i, n in enumerate(tree):
        if i:
            row = int(math.floor(math.log(i + 1, 2)))
        else:
            row = 0
        if row != last_row:
            output.write('\n')
        columns = 2 ** row
        col_width = int(math.floor(total_width / columns))
        output.write(str(n).center(col_width, fill))
        last_row = row
    print(output.getvalue())
    print('-' * total_width)
    print()
import heapq
from heapq_showtree import show_tree
from heapq_heapdata import data

heap = []
print('random :', data)
print()

for n in data:
    print('add {:>3}:'.format(n))
    heapq.heappush(heap, n)
    show_tree(heap)

Resultado de salida:

random : [19, 9, 4, 10, 11]

add  19:

                 19
------------------------------------

add   9:

                 9
        19
------------------------------------

add   4:

                 4
        19                9
------------------------------------

add  10:

                 4
        10                9
    19
------------------------------------

add  11:

                 4
        10                9
    19       11
------------------------------------

3. Enlace de referencia

  1. Análisis del módulo heapq en Python
  2. El módulo heapq en python3 usa

Supongo que te gusta

Origin blog.csdn.net/flyingluohaipeng/article/details/129728356
Recomendado
Clasificación