| Scopo | heapq implementa un algoritmo di ordinamento sul min-heap adatto all'uso con le liste di Python |
| Versione Python | Nuovo nella 2.3 con aggiunte nella 2.5 |
A partire dal 1 gennaio 2021 le versioni 2.x di Python non sono piu' supportate. Ti invito a consultare la corrispondente versione 3.x dell'articolo per il modulo heapq
Un heap è una struttura dati a forma di albero dove i nodi figli hanno una relazione di ordinamento con i genitori. Gli heap binari possono essere rappresentati usando una lista di array organizzati in modo che l figli dell'elemento N siano alle posizioni 2*N+1 e 2*N+2 (per indici a base zero). Questa caratteristica rende possibile riorganizzare gli heap sul posto, così che non sia necessario riallocare tanta memoria quando si aggiungono ed eliminano elementi.
Un max-heap assicura che il genitore sia più largo od uguale ad entrambi i suoi figli. Un min-heap richiede che il genitore sia minore od uguale ai suoi figli. Il modulo Python heapq implementa un min-heap.
L'esempio seguente usa questi dati campione:
# Questi dati sono stati generati con il modulo random.
data = [19, 9, 4, 10, 11, 8, 2]
Ci sono due metodi base per creare un heap,
heappush()
ed
heapify()
.
Usando heappush(), l'ordinamento degli elementi viene mantenuto mentre i nuovi elementi sono aggiunti da una sorgente di dati.
import heapq
from heapq_showtree import show_tree
from heapq_heapdata import data
heap = []
print 'random :', data
print
for n in data:
print 'aggiungo %3d:' % n
heapq.heappush(heap, n)
show_tree(heap)
$ python heapq_heappush.py
random : [19, 9, 4, 10, 11, 8, 2]
aggiungo 19:
19
------------------------------------
aggiungo 9:
9
19
------------------------------------
aggiungo 4:
4
19 9
------------------------------------
aggiungo 10:
4
10 9
19
------------------------------------
aggiungo 11:
4
10 9
19 11
------------------------------------
aggiungo 8:
4
10 8
19 11 9
------------------------------------
aggiungo 2:
2
10 4
19 11 9 8
Se i dati sono già in memoria, è più efficiente usare heapify() per risistemare gli elementi della lista sul posto.
import heapq
from heapq_showtree import show_tree
from heapq_heapdata import data
print 'random :', data
heapq.heapify(data)
print 'heapified :'
show_tree(data)
$ python heapq_heapify.py
random : [19, 9, 4, 10, 11, 8, 2]
heapified :
2
9 4
10 11 8 19
------------------------------------
Una volta che l'heap è organizzato correttamente, si usa
heappop()
per togliere l'elemento con il valore più basso. In questo esempio, adattato dalla documentazione della stdlib,
heapify()
e
heappop()
sono usati per ordinare una lista di numeri.
import heapq
from heapq_showtree import show_tree
from heapq_heapdata import data
print 'random :', data
heapq.heapify(data)
print 'heapified :'
show_tree(data)
print
inorder = []
while data:
smallest = heapq.heappop(data)
print 'pop %3d:' % smallest
show_tree(data)
inorder.append(smallest)
print 'ordinati :', inorder
$ python heapq_heappop.py
random : [19, 9, 4, 10, 11, 8, 2]
heapified :
2
9 4
10 11 8 19
------------------------------------
pop 2:
4
9 8
10 11 19
------------------------------------
pop 4:
8
9 19
10 11
------------------------------------
pop 8:
9
10 19
11
------------------------------------
pop 9:
10
11 19
------------------------------------
pop 10:
11
19
------------------------------------
pop 11:
19
------------------------------------
pop 19:
------------------------------------
ordinati : [2, 4, 8, 9, 10, 11, 19]
Per togliere elementi esistenti e sostituirli con nuovi valori in una sola operazione si usa
heapreplace()
import heapq
from heapq_showtree import show_tree
from heapq_heapdata import data
heapq.heapify(data)
print 'inizio:'
show_tree(data)
for n in [0, 7, 13, 9, 5]:
smallest = heapq.heapreplace(data, n)
print 'sostituzione di %2d con %2d:' % (smallest, n)
show_tree(data)
Questa tecnica consente di mantenere uno heap a dimensione fissa, come una coda di attività ordinate per priorità
$ python heapq_heapreplace.py
inizio:
2
9 4
10 11 8 19
------------------------------------
sostituzione di 2 con 0:
0
9 4
10 11 8 19
------------------------------------
sostituzione di 0 con 7:
4
9 7
10 11 8 19
------------------------------------
sostituzione di 4 con 13:
7
9 8
10 11 13 19
------------------------------------
sostituzione di 7 con 9:
8
9 9
10 11 13 19
------------------------------------
sostituzione di 8 con 5:
5
9 9
10 11 13 19
------------------------------------
heapq comprende anche 2 funzioni per esaminare un iterabile per trovare un intervallo dei valori più grandi o più piccoli che esso contiene. L'uso di
nlargest()
e
nsmallest()
è veramente efficace per valori relativamente piccoli di n>1, ma può comunque tornare comodo in qualche caso.
import heapq
from heapq_heapdata import data
print 'tutti :', data
print 'maggiori 3 :', heapq.nlargest(3, data)
print 'da ordinamento :', list(reversed(sorted(data)[-3:]))
print 'minori 3 :', heapq.nsmallest(3, data)
print 'da ordinamento :', sorted(data)[:3]
$ python heapq_extremes.py tutti : [19, 9, 4, 10, 11, 8, 2] maggiori 3 : [19, 11, 10] da ordinamento : [19, 11, 10] minori 3 : [2, 4, 8] da ordinamento : [2, 4, 8]
Vedere anche: