170 likes | 394 Views
Code a priorità (Heap). Definizione Heapify (mantenimento coda a priorità) Costruire un Heap Insert, Maximum e Extract-Max. Coda a priorità (Heap). Una coda a priorità può essere rappresentato da un albero binario completo.
E N D
Code a priorità (Heap) Definizione Heapify (mantenimento coda a priorità) Costruire un Heap Insert, Maximum e Extract-Max
Coda a priorità (Heap) • Una coda a priorità può essere rappresentato da un albero binario completo. • La chiave del padre è sempre maggiore di quella dei figli: key(i) ≤ key(parent(i)) . Albero binario completo: Sono riempiti tutti i livelli eccetto possibilmente l’ultimo. Altezza=Θ(log(n)) Coda a priorità: Il nodo a maggiore priorità (con la chiave più grande) sta in cima. Nota: si può ragionare in maniera analoga quando si pone che key(i) ≥ key(parent(i)). 16 10 14 8 7 9 3 2 4 1
Heap tramite un Array • Una coda a priorità può essere implementato tramite un’array (A). A[PARENT(i)] ≥ A[i]. 1 16 3 2 10 PARENT(j) • return 14 4 5 7 6 8 7 9 3 LEFT(i) • return 2i 8 9 10 2 4 1 RIGHT(i) • return 2i+1 length[A] heap-size[A] n 1 2 3 4 5 6 7 8 9 10 A … 7 14 10 8 9 3 2 16 4 1
Heapify (mantenimento coda a priorità) • Si sistema l’elemento A[i]: si suppone gli alberi con radice LEFT(i) e RIGHT(i) siano degli Heap. A[i] LEFT[i] RIGHT[i] HEAP HEAP
Heapify (mantenimento coda a priorità) • Si sistema l’elemento A[i]: si suppone gli alberi con radice LEFT(i) e RIGHT(i) siano degli Heap. HEAPIFY(A,i) // sistema A[i] nel Heap • l ← LEFT(i) // figlio sx • r ← RIGHT(i) // figlio dx • if l ≤ heap-size[A] and A[l] > A[i] // cerca il maggiore fra padre e • then magg ← l // i due figli (se ci sono…) • else magg ← i • if r ≤ heap-size[A] and A[r] > A[magg] • then magg ← r • if magg ≠ i // il magg è uno dei due figli… • then scambia A[i] ↔ A[magg] • HEAPIFY(A,magg)
Esempio Heapify • All’inizio si chiama HEAPIFY(A,2) 1 1 16 16 3 3 2 2 10 10 14 i 4 4 5 7 6 4 5 7 6 i 4 7 9 3 14 7 9 3 8 9 10 8 9 10 2 8 1 2 8 1
Esempio Heapify • Il costo in termine di tempo è nel caso peggio l’altezza dell’albero. O(h) = O(log(n)) 1 16 3 2 10 14 4 5 7 6 8 7 9 3 i 8 9 10 2 4 1
Costruire l’Heap BUILD-HEAP(A) // strategia bottom-up: dal basso verso l’alto • heap-size[A] ← length[A] // • for i ← length[A]/2 downto 1 // dalla metà in su • do HEAPIFY(A,i) // sotto la metà sono tutte foglie • Il costo di HEAPIFY è O(log(n)) e viene chiamato O(n) volte. Quindi un limite del caso peggiore è O(n log(n)). • In realtà, il caso peggiore può essere stimato come O(n). =2 Rappresenta il massimo numero di sottoalberi pieni ad altezza h (avendo a disposizione n elementi)
Esempio costruzione Heap 6 7 8 9 10 1 2 3 4 5 A 3 2 9 10 14 16 8 7 1 4 Foglie Si comincia da qua 1 1 4 4 3 3 2 2 3 3 1 1 4 5 7 6 4 5 7 6 i 2 16 9 10 i 2 16 9 10 8 9 10 8 9 10 14 8 7 14 8 7
Esempio costruzione Heap Strategia button-up: dal basso verso l’alto si chiama HEAPIFY su tutte i nodi interni. 1 1 4 4 3 3 2 2 10 i i 3 1 1 4 5 7 6 4 5 7 6 14 16 9 3 14 16 9 10 8 9 10 8 9 10 2 8 7 2 8 7
Esempio costruzione Heap Strategia button-up: dal basso verso l’alto si chiama HEAPIFY su tutte i nodi interni. 1 1 i 16 4 3 3 2 2 10 3 14 16 4 5 7 6 4 5 7 6 8 7 9 3 14 7 9 10 8 9 10 8 9 10 2 4 1 2 8 1
Altre operazioni • MAXIMUM(A): ritorna l’elemento a massima priorità, ossia quello in cima. • EXTRACT-MAX(A): estrae l’elemento a massima priorità, successivamente l’Heap andrebbe sistemato • INSERT(A): inserisce un nuovo elemento nel Heap.
MAXIMUM e EXTRACT-MAX MAXIMUM(A) ha un tempo di esecuzione costante, O(1) MAXIMUM(A) // restituisci l’elem. a magg. priorità, • return A[1] // ossia quello in cima EXTRACT-MAX(A) ha un tempo di esecuzione O(log(n)),dovuto alla chiamata HEAPIFY(). EXTRACT-MAX(A) // Estrae elemento a maggiore priorità • ifheap-size[A] < 1 // heap vuoto? • then error “heap underflow” • max← A[1] // memorizza elem. In cima • A[1]← A[heap-size[A]] // metti l’ultimo elemento in cima • heap-size[A]← heap-size[A] – 1 // heap diminuisce di 1 elem. • HEAPIFY(A,1) // HEAPIFY sul 1° elem. • return max // restituisci l’elem. a magg. priorità
HEAP-INSERT HEAP-INSERT(A, KEY) ha un tempo di esecuzione O(log(n)),nel caso peggiore si risale l’albero dalla foglia alla radice. HEAP-INSERT(A, key) // Inserisci elemento nell’Heap • heap-size[A]← heap-size[A] + 1 // aumenta Heap di 1 elemento • i← heap-size[A] // inizia dall’elem. inserito (ultimo) • while i > 1 and A[PARENT(i)]<key // il nuovo elem. Viene fatto • do A[i] ← A[PARENT(i)] // risalire… • i← PARENT(i) • A[i] ← key // fino a trovare il suo posto
Inserimento in un Heap HEAP-INSERT(A, 15) key=15 L’Heap viene aumentato di un elemento. Si procede poi a risalire l’albero per trovare il suo posto. 1 1 16 16 3 3 2 2 10 3 14 14 4 5 7 6 4 5 7 6 i 8 7 9 3 8 7 9 10 11 8 9 10 8 9 11 10 7 2 4 1 i 2 4 1 8 Nuovo elemento key = 15
Inserimento in un Heap HEAP-INSERT(A, 15) key=15 L’Heap viene aumentato di un elemento. Si procede poi a risalire l’albero per trovare il suo posto. 1 1 16 16 3 3 2 2 10 3 15 i 14 4 5 7 6 4 5 7 6 8 14 9 3 8 14 9 10 11 8 9 10 8 9 11 10 7 2 4 1 2 4 1 7
Considerazioni • La struttura dati Heap gestisce una coda a priorità. • Viene estratto l’elemento a maggiore priorità (es. quello con chiave maggiore) • Si può invertire la relazione con il padre, se key(i) ≥ key(parent(i)). • In questo caso l’elemento a maggiore priorità è l’elemento più piccolo • Heap-sort: algoritmo di ordinamento che usa un Heap. Si estrae ogni volta l’elemento più piccolo fino ad ottenere un vettore ordinato. Tempo O(n log(n)).