Title: Heap Ordinamento e code di priorit
1HeapOrdinamento e code di priorità
- Laboratorio di Algoritmi 02/03
- Prof. Ugo de Liguoro
2Heap definizione
- Definizione. Uno Heap (binario) è un albero
binario finito i cui vertici sono etichettati da
elementi di un insieme linearmente ordinato
(chiavi), che soddisfa - 1. Se v è figlio di v' allora chiave(v) ?
chiave(v') - 2. Lalbero è completo salvo al più lultimo
livello, che è riempito da - sinistra.
- Uno heap binario può essere realizzato come un
vettore H di dimensione pari alla cardinalità
dellalbero e tale che - H1 sia la radice dellalbero
- H2i e H2i1 siano rispettivamente il figlio
sinistro e quello destro di Hi. - Ne segue che lelemento la cui etichetta è
massima tra tutte quelle dei vertici dellalbero,
è la radice ossia H1.
3Heap esempio
16
9
14
7
4
8
10
3
2
1
16 9 14 7 4 8 10 3 2 1
H
1 2 3 4 5 6 7 8 9 10
4Left, Right, Parent
Per muoversi allinterno di uno heap
rappresentato come un vettore sono utili le
seguenti funzioni
// fissato uno heap h e la sua dimensione
HeapSize(h) Parent(i) ?i / 2? // se i ?
0 Left(i) if 2i lt HeapSize(h) then 2i else
i Right(i) if 2i1 lt HeapSize(h) then 2i1 else
i
5Inserimento2
Per inserire un nuovo elemento in uno heap,
Insert lo aggiunge come foglia dellalbero
quindi la fa risalire lungo il ramo cui è stato
aggiunto sinché non sia ricostruito lo heap.
Insert (h heap x key) HeapSize(h)
HeapSize(h)1 i HeapSize(h) hi x while i
gt 1 and hParent(i) lt hi do exchange(hi,
hParent(i)) i Parent(i)
Nota la complessità è dellordine della
lunghezza del ramo ossia O(log n)
6Heap Inserimento (1)
16
9
14
7
4
8
10
3
2
1
15
7Heap Inserimento (2)
16
9
14
7
8
10
15
3
4
2
1
8Heap Inserimento (3)
16
15
14
7
9
8
10
3
4
2
1
9Heap Inserimento (4)
16
15
14
7
9
8
10
3
4
2
1
10Estrazione
Lestrazione da uno heap avviene dalla radice.
Consta di due fasi 1) lelemento più a destra
dellultimo livello rimpiazza la radice 2)
lelemento ora in radice viene fatto discendere
lungo lalbero finché non sia maggiore di
entrambi i figli nel discendere si sceglie
sempre il figlio col valore massimo della chiave.
ExtractMaximum (h heap) h1
hHeapSize(h) HeapSize(h) HeapSize(h) -
1 Heapify(h,1) // Fase (2)
Fase (1)
11Ricostruzione dello heap
La fase (2), di cui si incarica Heapify, è più
generale, poiché questa funzione può iniziare il
suo lavoro in qualunque punto i dello heap,
purché i sottoalberi con radice in Left(i) e
Right(i) siano a loro volta degli heap
Heapify (h heap i index) largest index of
maxhi,hLeft(i),hRight(i) if largest ? i
then exchange(hi,hlargest) Heapify(h,larges
t)
Nota se n è la cardinalità dellalbero con
radice in i, allora Heapify è O(log n) (caso
peggiore).
12Heap Estrazione (1)
16
15
14
7
9
8
10
3
4
2
1
13Heap Estrazione (2)
4
15
14
7
9
8
10
3
2
1
14Heap Estrazione (3)
15
4
14
7
9
8
10
3
2
1
15Heap Estrazione (4)
15
9
14
7
4
8
10
3
2
1
16Heap Estrazione (5)
15
9
14
7
4
8
10
3
2
1
17Usi di uno heap
- La struttura heap può essere impiegata per
- implementare code di priorità
- realizzare un algoritmo di ordinamento ottimo,
HeapSort.
18Code di priorità (ADT)
Una coda di priorità è un insieme finito S di
oggetti su cui è definita una funzione priorità
S ? Nat. Le operazioni definite su di essa sono
illustrate nella seguente specfica ADT datatype
PriorityQueue, Element constructors EmptyQueue
PriorityQueue Insert PriorityQueue, Element -gt
PriorityQueue ExtractMaximum PriorityQueue -gt
PriorityQueue observations Maximum
PriorityQueue -gt Element semantics Insert(S,x)
S ? x Maximum(S) x tale che Priorità(x)
max Priorità(y) y ?
S ExtractMaximum(S) S \ Maximum(S)
19Code di priorità implementazione
Si possono implementare con gli heap la funzione
priorità si implementa codificando ogni elemento
come una coppia ?elemento, priorità?, e
strutturando lo heap in base alla seconda
coordinata di ciascuna coppia (la chiave). Le
funzioni Insert e ExtractMaximum sono quelle
viste la funzione Maximum è semplicemente
Maximum (h heap) return h1 // il massimo è
sempre in radice
La funzione, non essendo distruttiva, non
richiede infatti alcuna ricostruzione dello heap,
ed ha complessità O(1).
20Heapsort (1)
Si può sfruttare la struttura dati heap per
costruire un algoritmo di ordinamento simile, per
struttura, al SelectSort con selezione del
massimo.
i
1
n
V
V1..i è uno heap
Vi1..n è ordinato
? x ? V1..i ? y ? Vi1..n. x ? y
HeapSort(v array) BuildHeap(v) // riorganizza v
in uno heap for i Length(v) downto 2
do exchange(v1,vi) HeapSize(v)
HeapSize(v) - 1 Heapify(v,1)
21HeapSort (2)
BuildHeap. Se v1..n è un vettore qualsiasi,
BuildHeap(v) lo riorganizza in modo che sia uno
heap. Pensando h?n/2? 1 .. n come le foglie
dellalbero che diventerà uno heap, la condizione
che Left(?n/2? 1 ) e Right(?n/2? 1 ) siano heap
è trivialmente soddisfatta, onde possiamo iterare
Heapify da ?n/2? a 1
BuildHeap(v array) for i ?length(v)/2? downto
1 do Heapify(v,i)
Nota un confine superiore alla complessità di
BuildHeap è O(n log n) (si itera una procedura
O(log n) per ciascuno degli n vertici). Questa
stima grossolana si può raffinare sino a mostrare
che in realtà BuildHeap è lineare.
22Heapsort (3)
A differenza del SelctSort, che è O(n2), HeapSort
ha complessità O(n log n), quindi è un algoritmo
ottimo per lordinamento. Ciò si deve
allefficienza della selezione del massimo nel
semivettore sinistro, che ha complessità
logaritmica
HeapSort(v array) BuildHeap(v) // O(n log n) (o
meglio O(n)) for i Length(v) downto 2 do //
O(n) cicli exchange(v1,vi) HeapSize(v)
HeapSize(v) - 1 Heapify(v,1) // O(log n)
Allora O(n) O(n) O(log n) O(n) O(n log n)
O(n log n).
23Heap fine.