Sei sulla pagina 1di 8

11/24/2008 9:39 AM

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

Heap-Order: per ogni nodo v radice

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

Albero binario completo: dato un heap di altezza h

Laboratorio di Algoritmi e Strutture Dati 2008-09

Laboratorio di Algoritmi e Strutture Dati 2008-09

Esempio

Il TDA CompleteBinaryTree

Specializza il TDA BinaryTree Supporta i metodi addizionali

3 5 8 10 9 11 12 7 4 10

Position<E> add(E o):

Inserisce una foglia che contiene lelemento o

La nuova foglia ha come padre il primo nodo dellalbero che ha meno di 2 figli

Restituisce la position della nuova foglia

E remove() rimuove lultimo nodo z dellalbero

restituisce lelemento di z
Laboratorio di Algoritmi e Strutture Dati 2008-09

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;

Laboratorio di Algoritmi e Strutture Dati 2008-09

Laboratorio di Algoritmi e Strutture Dati 2008-09

10

Implementazione con i vettori

La classe innestata BTPos


protected static class BTPos<E> implements Position<E> { E element; int index; public BTPos(E elt, int i) { element = elt; index = i; } public E element() { return element; } public int index() { return index; }

Per un albero con n nodi si usa un vettore di dimensione n+1

entrata di rango 0 vuota Il figlio sinistro ha indice 2i Il figlio destro ha indice 2i+1
2 5 9 7 6

Per un nodo di indice i


2 0 1

5 2

6 3

9 4

7 5
}

public E setElement(E elt) { E temp = element; element = elt; return temp; }

Laboratorio di Algoritmi e Strutture Dati 2008-09

Laboratorio di Algoritmi e Strutture Dati 2008-09

11

Implementazione con i vettori

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 un Array list T IndexList<BTPos<E>> T Lentrata di indice 0 si pone uguale a null

Il numero di elementi nellheap sar pari a T.size() -1

Si usa la classe BTPos (implementa Position) per rappresentare gli elementi nei nodi

2 variabili di istanza:

element index (indice della posizione nel vettore)

Laboratorio di Algoritmi e Strutture Dati 2008-09

Laboratorio di Algoritmi e Strutture Dati 2008-09

12

11/24/2008 9:39 AM

I metodi remove e add


public E remove() throws EmptyTreeException { if(isEmpty()) throw new EmptyTreeException(Lalbero vuoto"); return T.remove(size()).element(); //size()=T.size()-1 } public Position<E> add(E e) { int i = size() + 1; // size() + 1=T.size() BTPos<E> p = new BTPos<E>(e,i); T.add(i, p); return p; }
Laboratorio di Algoritmi e Strutture Dati 2008-09 13

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()); }

PriorityQueue implementata con heap

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)

Laboratorio di Algoritmi e Strutture Dati 2008-09

14

Laboratorio di Algoritmi e Strutture Dati 2008-09

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

Nodo padre della nuova foglia


Laboratorio di Algoritmi e Strutture Dati 2008-09 18

11/24/2008 9:39 AM

Ripristino dellheap-order

Inserimento della chiave 1

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

19

Laboratorio di Algoritmi e Strutture Dati 2008-09

22

Inserimento della chiave 1

Inserimento della chiave 1

8 7

14

10

14

10

13

12

15

13

12

15

Laboratorio di Algoritmi e Strutture Dati 2008-09

20

Laboratorio di Algoritmi e Strutture Dati 2008-09

23

Inserimento della chiave 1

Inserimento della chiave 1

8 7

14

10

14

10

13

12

15

13

12

15

Laboratorio di Algoritmi e Strutture Dati 2008-09

21

Laboratorio di Algoritmi e Strutture Dati 2008-09

24

11/24/2008 9:39 AM

removeMin

Cancellazione del minimo

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

25

Laboratorio di Algoritmi e Strutture Dati 2008-09

28

Downheap

Cancellazione del minimo

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

29

Cancellazione del minimo

Cancellazione del minimo

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

27

Laboratorio di Algoritmi e Strutture Dati 2008-09

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"); }

Laboratorio di Algoritmi e Strutture Dati 2008-09

31

Laboratorio di Algoritmi e Strutture Dati 2008-09

34

La classe innestata MyEntry


protected static class MyEntry<K,V> implements Entry<K,V> { protected K key; protected V value; public MyEntry(K k, V v) { key = k; value = v; } public K getKey() { return key; } public V getValue() { return value; } public String toString() { return "(" + key + "," + value + ")"; } }
Laboratorio di Algoritmi e Strutture Dati 2008-09

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

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

Laboratorio di Algoritmi e Strutture Dati 2008-09

39

Laboratorio di Algoritmi e Strutture Dati 2008-09

42

11/24/2008 9:39 AM

Costruzione bottom-up di un heap


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

Laboratorio di Algoritmi e Strutture Dati 2008-09

43

Costruzione bottom-up di un heap


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

Laboratorio di Algoritmi e Strutture Dati 2008-09

Potrebbero piacerti anche