Capitolo 5: Heap e code con priorità
Heap e code con priorità
Un heap può essere paragonato ad un albero binario i cui nodi contengono dei
dati e sono identificati da chiavi, inoltre la struttura deve soddisfare le seguenti
proprietà:
• tutte le foglie dell’heap hanno altezza h o h-1 per un valore opportuno di
h;
• le foglie di altezza h-1 (se ce ne sono) sono “a destra” delle foglie di
altezza h;
• per ogni nodo, la chiave del nodo è minore o uguale delle chiave dei figli.
•
Facciamo un esempio grafico.
Per semplificare la gestione dell’heap si usa di solito rappresentarlo con un
vettore: in particolare se l’heap è formato da N nodi avremo un vettore a di N
elementi.
In questa nuova struttura ogni nodo di posizione i avrà il figlio sinistro nella
posizione 2i e figlio destro nella posizione 2i+1.
50
Capitolo 5: Heap e code con priorità
Il vettore inoltre avrà le seguenti proprietà:
• un nodo di indice i avrà entrambi i figli se 2i+1 ≤ N
• l’unico eventuale nodo che ha solo un figlio, il figlio sinistro, ha indice i
tale che 2i+1 ≥ N e 2i ≤ N
• gli altri nodi sono foglie.
Da quanto detto è semplice capire che tutti i nodi da indice 1 ≤ i ≤ (N-1)/2 hanno
due figli; i nodi con indice maggiore di N/2 sono foglie e se N è pari il nodo di
indice N/2 ha solo un figlio.
1
2
3
4
5
6
7
8
9
10
11
12
Rappresentazione
3
7
8
25
22
12
11
48
30
39
36
18
vettore dell’heap mostrato in
con
alto.
Un problema riscontrabile con l’heap è l’inserimento di un elemento che
potrebbe violare le proprietà della struttura. Infatti se inseriamo un nodo a[i]
potrebbe accadere che il padre di a[i] abbia ora chiave maggiore di a[i] o
viceversa può succedere che il nodo inserito abbia chiave maggiore dei suoi due
figli. Per risolvere questo inconveniente bisognerà far salire o scendere il nuovo
nodo lungo l’albero in modo da inserirlo nella corretta posizione.
Mostriamo graficamente come avviene questo procedimento.
51
Capitolo 5: Heap e code con priorità
Inserimento di elemento nell’heap
Rimozione di elemento dall’heap
52
Capitolo 5: Heap e code con priorità
La seguente procedura consente di riaggiustare l’heap in caso di inserimento o
rimozione di un elemento.
type
data=record
chiave:integer;
valore:integer;
end;
vettore=array[1..N] of data;
procedure heapify(var a:vettore; i,j,r:integer);
{ - i : indice del nodo modificato
- j : indice del primo elemento dell’heap
- r : indice dell’ultimo elemento dell’heap
}
var
temp:data;
figlio:integer;
begin
temp:=a[i];
while (i >= j ) and (temp.key < a[ i div 2].key) do begin
a[i]:=a[ i div 2];
i:=i div 2;
end;
a[i]:=temp;
while (i <= r div 2) do begin
figlio:=2*i;
if (figlio+1 <= r) and (a[figlio+1].key < a[figlio].key) then
figlio:=figlio+1;
if (temp.key<=a[figlio].key) then exit {forza il ciclo e esci};
a[i]:=a[figlio];
i:=figlio;
end;
a[i]:=temp;
end;
53
Capitolo 5: Heap e code con priorità
Grazie a questa procedura possiamo facilmente aggiungere e rimuovere un
elemento dall’heap, in particolare per aggiungerlo basta inserire il nuovo
elemento nella posizione di indice N+1,come se fosse una foglia, e poi sarà la
procedura a rimettere al posto giusto l’elemento.
a[N+1]:=nuovo elemento;
heapify(N,1,N+1);
Per eliminare un elemento di indice i invece esso sarà sostituito dalla’elemento
di posizione N, sarà decrementato il valore di N e quindi la procedura riordinerà
l’heap.
A[i]:=a[N];
heapify(i,1,N-1);
54
Capitolo 5: Heap e code con priorità
Bibliografia
- Alan Bertossi, Algoritmi e strutture di dati
Casa editrice UTET Libreria 2004
55