Altezza di un heap
Heap
Un heap che memorizza n chiavi ha altezza log n Dimostrazione: Sia h laltezza dellalbero
Ci sono 2i chiavi a profondit i = 0, , h - 1 ed almeno una chiave a profondit h n 1 + 2 + 4 + + 2h-1 + 1 = 2h quindi h log n
profondit chiavi 0 1 1 2
h-1 h
Laboratorio di Algoritmi e Strutture Dati 2008-09
2h-1 1
Laboratorio di Algoritmi e Strutture Dati 2008-09
Definizione
Altezza di un heap
Un heap un albero binario che contiene entrate della forma (key, value) nei suoi nodi e soddisfa le seguenti propriet:
Daltra parte sappiamo che il numero max di nodi di un albero binario di altezza h h h+1-1 n 1 + 2 + 4 + + 2 = 2 2h n 2h+1-1 log(n+1)-1 h log n log(n)-1 < h log n h = log n
key(v) key(parent(v)) per i = 0, , h - 1, ci sono 2i nodi di profondit i (tutti i livelli, salvo al pi lultimo, sono pieni) Lultimo livello riempito da sinistra verso destra
Esempio
Il TDA CompleteBinaryTree
3 5 8 10 9 11 12 7 4 10
La nuova foglia ha come padre il primo nodo dellalbero che ha meno di 2 figli
restituisce lelemento di z
Laboratorio di Algoritmi e Strutture Dati 2008-09
11/24/2008 9:39 AM
Linterfaccia CompleteBinaryTree
public interface CompleteBinaryTree <E> extends BinaryTree <E> { public Position <E> add(E elem); public E remove(); }
ArrayListCompleteBinaryTree
public class ArrayListCompleteBinaryTree<E> implements CompleteBinaryTree<E> { IndexList<BTPos<E>> T;
10
entrata di rango 0 vuota Il figlio sinistro ha indice 2i Il figlio destro ha indice 2i+1
2 5 9 7 6
2 0 1
5 2
6 3
9 4
7 5
}
11
Il metodo checkPosition
protected BTPos<E>checkPosition(Position<E> v) throws InvalidPositionException { if (v == null || !(v instanceof BTPos)) throw new InvalidPositionException(La posizione non valida"); return (BTPos<E>) v; }
Si usa la classe BTPos (implementa Position) per rappresentare gli elementi nei nodi
2 variabili di istanza:
12
11/24/2008 9:39 AM
Il metodo iterator
public Iterator<E> iterator() { IndexList<E> list = new ArrayIndexList<E>(); Iterator<BTPos<E>> iter = T.iterator(); iter.next(); // il primo elemento null int i=0; while (iter.hasNext()) list.add(i++,iter.next().element()); return list.iterator(); }
Laboratorio di Algoritmi e Strutture Dati 2008-09 16
Il metodo hasLeft
public boolean hasLeft(Position<E> v) throws InvalidPositionException { BTPos<E> vv = checkPosition(v); return (2*vv.index() <= size()); }
Immagazziniamo un entrata (key, element) in ciascun nodo Un comparatore comp definisce la relazione di ordine totale tra le chiavi
(2, Sue) (5, Pat) (9, Jeff) (7, Anna) (6, Mark)
14
17
Il metodo positions()
public Iterable<Position<E>> positions() { IndexList<Position<E>> P = new ArrayIndexList<Position<E>>(); Iterator<BTPos<E>> iter = T.iterator(); iter.next(); //il primo elemento di T null int i=0; while (iter.hasNext()) P.add(i++,iter.next()); return P; }
Laboratorio di Algoritmi e Strutture Dati 2008-09 15
insert
Il metodo insert del TDA PriorityQueue corrisponde allinserimento di unentrata (k,v) nellheap Si svolge in 3 passi Immagazzina (k,v) in un nuovo nodo e lo aggiunge allheap mediante il metodo add() Ristabilisce lheap-order
2 5 9 7 2
6 9
5 7 1
11/24/2008 9:39 AM
Ripristino dellheap-order
Lalgoritmo upheap ripristina lheap-order scambiando (k,v) con le entrate dei suoi antenati fino a che (k,v) raggiunge la radice o si incontra un antenato con chiave minore di k
2
Siccome un heap ha altezza O(log n), lalgoritmo upheap ha tempo di esecuzione in O(log n) time
2 5 1 7 5 9 7 1 2
13 7
14
10
12
15
19
22
8 7
14
10
14
10
13
12
15
13
12
15
20
23
8 7
14
10
14
10
13
12
15
13
12
15
21
24
11/24/2008 9:39 AM
removeMin
Il metodo removeMin del TDA PriorityQueue implementato rimuovendo lentrata nella radice dellheap Lalgoritmo di rimozione consiste di 3 passi: Sostituisci lentrata della radice con lentrata dellultimo nodo w Rimuovi w con remove() Ripristina lheap-order che potrebbe essere stato violato dalla sostituzione dellentrata della radice
2 5 9 7 6
16
9 5 15 25 10 7 12 11 8 6 23
7 5 9 6
w
ultimo nodo
25
28
Downheap
Lalgoritmo downheap ripristina lheap-order scambiando ad ogni passo lentrata (k,v) con lentrata del figlio che ha chiave pi piccola Lalgoritmo downheap termina quando (k,v) raggiunge un nodo z tale che z una foglia o le chiavi dei figli di z sono maggiori di k Siccome laltezza dellheap O(log n), downheap ha tempo di esecuzione O(log n)
7 5 9 6 9
Laboratorio di Algoritmi e Strutture Dati 2008-09
5 9 15 16 25 10 7 12 11 8 6 23
5 7 6
26
29
4 5 15 16 25 10 7 12 11 8 9 6 23 16 15 25 10 7 9 12
5 6 8 11 23
27
30
11/24/2008 9:39 AM
La classe HeapPriorityQueue
public class HeapPriorityQueue<K,V> implements PriorityQueue<K,V> { protected CompleteBinaryTree<Entry<K,V>> heap; protected Comparator<K> comp;
La classe HeapPriorityQueue
protected void checkKey(K key) throws InvalidKeyException { try { comp.compare(key,key); } catch(Exception e) { throw new InvalidKeyException(chiave non valida"); }
31
34
La classe HeapPriorityQueue
public Entry<K,V> insert(K k, V x) throws InvalidKeyException { checkKey(k); Entry<K,V> entry = new MyEntry<K,V>(k,x); upHeap(heap.add(entry)); return entry; }
32
35
La classe HeapPriorityQueue
public HeapPriorityQueue() { heap = new ArrayListCompleteBinaryTree<Entry<K,V>>(); comp = new DefaultComparator<K>(); } public HeapPriorityQueue(Comparator<K> c) { heap = new ArrayListCompleteBinaryTree<Entry<K,V>>(); comp = c; } public int size() { return heap.size(); } public boolean isEmpty() { return heap.size() == 0; }
Laboratorio di Algoritmi e Strutture Dati 2008-09 33
La classe HeapPriorityQueue
protected void upHeap(Position<Entry<K,V>> v) { Position<Entry<K,V>> u; while (!heap.isRoot(v)) { u = heap.parent(v); if (comp.compare(u.element().getKey(), v.element().getKey()) <= 0) break; swap(u, v); v = u; } }
Laboratorio di Algoritmi e Strutture Dati 2008-09 36
11/24/2008 9:39 AM
La classe HeapPriorityQueue
public Entry<K,V> removeMin() throws EmptyPriorityQueueException { if (isEmpty()) throw new EmptyPriorityQueueException(Coda a priorit vuota"); Entry<K,V> min = heap.root().element(); if (size() == 1) heap.remove(); else { heap.replace(heap.root(), heap.remove()); downHeap(heap.root()); } return min; }
Laboratorio di Algoritmi e Strutture Dati 2008-09 37
Esercizi
Implementare un algoritmo di ordinamento (HeapSort) che usa come struttura ausiliaria una PriorityQueue implementata con heap. Discuterne la complessit computazionale. Scrivere una classe PQStack che implementa Stack ed ha solo due variabili di istanza una delle quali di tipo PriorityQueue
40
La classe HeapPriorityQueue
protected void downHeap(Position<Entry<K,V>> r) { while (heap.isInternal(r)) { Position<Entry<K,V>> s; if (!heap.hasRight(r)) s = heap.left(r); else if (comp.compare(heap.left(r).element().getKey(), heap.right(r).element().getKey()) <=0) s = heap.left(r); else s = heap.right(r); if (comp.compare(s.element().getKey(), r.element().getKey())<0) { swap(r, s); r = s; } else break; } //fine while Laboratorio di Algoritmi e Strutture Dati } 38 2008-09
Nota
Se conosciamo in anticipo gli elementi che costituiscono la coda a priorit allora possiamo costruire lheap che implementa la coda a priorit in tempo lineare
Non invochiamo n volte insert() sulla coda come nel codice nella prossima slide Si usa lalgoritmo analizzato durante il corso di ASD per costruire lheap
41
La classe HeapPriorityQueue
protected void swap(Position<Entry<K,V>> x, Position<Entry<K,V>> y) { Entry<K,V> temp = x.element(); heap.replace(x, y.element()); heap.replace(y, temp); }
Esercizio
Aggiungere alla classe HeapPriorityQueue costruttore HeapPriorityQueue(V v[] , K k[]) che costruisce la coda a priorit in tempo lineare
il
39
42
11/24/2008 9:39 AM
Inseriamo tutti le entrate nellalbero Ripristiniamo heap-order dal basso verso lalto Per ogni i=1,,h, invochiamo down-heap su tutti i nodi di altezza i
h h-1 1 2
altezza #sottoaberi
2h-1
43
Possiamo costruire un heap contenente n chiavi in h = O(log n ) fasi Dopo la fase i, tutti i sottoalberi di altezza i soddisfano lheap-order. Ogni fase richiede tempo O(i2h-i) Questa lidea di Build-Heap vista durante il corso di ASD 2h-i sottoalberi di altezza i
2i+1 1
2i+1 1
2i+1 1
2i+1 1
44