La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Heap Ordinamento e code di priorità Ugo de Liguoro.

Presentazioni simili


Presentazione sul tema: "Heap Ordinamento e code di priorità Ugo de Liguoro."— Transcript della presentazione:

1 Heap Ordinamento e code di priorità Ugo de Liguoro

2 Heap: 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: H[1] sia la radice dellalbero H[2i] e H[2i+1] siano rispettivamente il figlio sinistro e quello destro di H[i]. Ne segue che lelemento la cui etichetta è maggiore tra tutte quelle dei vertici dellalbero, è la radice ossia H[1].

3 Heap: esempio 16 9 14 7 4810 3 21 16 9 14 7 4 8 10 3 2 1 1 2 3 4 5 6 7 8 9 10 H =

4 Left, 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 < HeapSize(h) then 2i else i Right(i) = if 2i+1 < HeapSize(h) then 2i+1 else i

5 Inserimento 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) h[i] = x while i > 1 and h[Parent(i)] < h[i] do exchange(h[i], h[Parent(i)]) i := Parent(i) Nota: la complessità è dellordine della lunghezza del ramo ossia O(log n)

6 Heap: Inserimento (1) 16 9 14 7 4810 3 2115

7 Heap: Inserimento (2) 16 9 14 7 4 810 3 21 15

8 Heap: Inserimento (3) 16 9 14 7 4 810 3 21 15

9 Heap: Inserimento (4) 16 9 14 7 4 810 3 21 15

10 Estrazione 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) h[1] := h[HeapSize(h)] HeapSize(h) := HeapSize(h) - 1 Heapify(h,1) // Fase (2) Fase (1)

11 Heapify (h: heap; i: index) largest := index of max{h[i],h[Left(i)],h[Right(i)]} if largest i then exchange(h[i],h[largest]) Heapify(h,largest) 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: Ricostruzione di uno heap Nota: se n è la cardinalità dellalbero con radice in i, allora Heapify è O(log n) (caso peggiore).

12 Heap: Estrazione (1) 16 9 14 7 4 810 3 21 15

13 Heap: Estrazione (2) 4 9 14 7 810 3 21 15

14 Heap: Estrazione (3) 4 9 14 7 810 3 21 15

15 Heap: Estrazione (4) 4 9 14 7 810 3 21 15

16 Heap: Estrazione (5) 4 9 14 7 810 3 21 15

17 Usi di uno heap La struttura heap può essere impiegata per: implementare code di priorità; realizzare un algoritmo di ordinamento ottimo, HeapSort.

18 Code 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 -> PriorityQueue ExtractMaximum: PriorityQueue -> PriorityQueue observations: Maximum: PriorityQueue -> Element semantics: Insert(S,x) = S {x} Maximum(S) = x tale che Priorità(x) = max {Priorità(y)| y S} ExtractMaximum(S) = S \ {Maximum(S)}

19 Code di priorità: implementazione Si possono implementare con gli heap: la funzione priorità si implementa codificando ogni elemento come una coppia elemento, priorità (usando le strutture del C), 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 h[1] // il massimo è sempre in radice La funzione, non essendo distruttiva, non richiede infatti alcuna ricostruzione dello heap, ed ha complessità O(1).

20 Heapsort (1) Si può sfruttare la struttura dati heap per costruire un algoritmo di ordinamento simile, per struttura, al SelectSort con selezione del massimo. i V 1n V[1..i] è uno heapV[i+1..n] è ordinato x V[1..i] y V[i+1..n]. x y HeapSort(v: array) BuildHeap(v) // riorganizza v in uno heap for i := Length(v) downto 2 do exchange(v[1],v[i]) HeapSize(v) := HeapSize(v) - 1 Heapify(v,1)

21 HeapSort (2) BuildHeap. Se v[1..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.

22 Heapsort (3) A differenza del SelctSort, che è O(n 2 ), 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(v[1],v[i]) 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).

23 Heap: fine.


Scaricare ppt "Heap Ordinamento e code di priorità Ugo de Liguoro."

Presentazioni simili


Annunci Google