370 likes | 646 Views
heap. concetti ed applicazioni. heap. heap = catasta condizione di heap albero binario perfettamente bilanciato tutte le foglie sono “a sinistra” ma non è un BST!! ogni nodo contiene una chiave maggiore o eguale di quelle presenti negli eventuali figli non è una struttura ordinata
E N D
heap concetti ed applicazioni
heap • heap = catasta • condizione di heap • albero binario perfettamente bilanciato • tutte le foglie sono “a sinistra” • ma non è un BST!! • ogni nodo contiene una chiave maggiore o eguale di quelle presenti negli eventuali figli • non è una struttura ordinata • le visite in ampiezza e in pre- in- post-ordine non forniscono un ordinamento delle chiavi ASD - Heap
89 89 67 68 67 68 66 65 66 67 66 65 66 1 66 66 5 4 64 1 2 3 4 5 6 67 67 67 67 66 65 67 67 67 67 1 heap? 89 ASD - Heap
6 13 22 13 23 44 27 23 32 33 24 56 81 min-heap max- e min-heap • la struttura definita è detta max-heap • variante: min-heap • ogni nodo contiene una chiave minore o eguale di quelle presenti negli eventuali figli ASD - Heap
operazioni su un (max-)heap • insert chiave • inserisce nuova chiave nello heap • occorre mantenere la condizione di heap • deleteMax • cancella chiave max dallo heap • occorre mantenere la condizione di heap • getMax • restituisce la chiave max nello heap • non modifica lo heap ASD - Heap
rappresentazione degli heap • tutte le rappresentazione usate per gli alberi binarie sono ammissibili • rappresentazione collegata, eventualmente con puntatori figli-genitore • rappresentazione tramite array • particolarmente efficiente ASD - Heap
89 67 68 89 0 67 1 66 65 66 67 68 2 66 3 1 43 21 5 4 64 65 4 66 5 67 6 1 7 43 8 21 9 5 10 4 11 64 12 rappresentazione tramite array • ogni nodo v è memorizzato in posizione p(v ) • se v è la radice allora p(v )=0 • se v è il figlio sinistro di u allora p(v )=2p(u )+1 • se v è il figlio destro di u allora p(v )=2p(u )+2
heap su array • vantaggi • grande efficienza in termini di spazio • l’occupazione può essere minima • facilità di navigazione • genitore i figli j • j = 2i + 1, 2i + 2 • figlio i genitore j • j = (i – 1) / 2 • svantaggio • implementazione statica • possono essere necessari progressivi raddoppiamenti/dimezzamenti dell’array di supporto ASD - Heap
rappresentazione in Java public class Heap { public static final int DEFAULTCAPACITY = 50; protected int storage[], size; public Heap() { this(DEFAULTCAPACITY); } public Heap(int dim) { storage = new int[dim]; size = 0; } // metodi… ASD - Heap
rappresentazione in Java/2 public boolean isLeaf(int i) { return getLeftIndex(i) >= size; } public boolean isRoot(int i) { return i == 0; } public boolean isEmpty() { return size == 0; } public boolean isFull() { return size == storage.length; } ASD - Heap
rappresentazione in Java/3 private static int getLeftIndex(int i) { return 2 * i + 1; } private static int getRightIndex(int i) { return getLeftIndex(i) + 1; } private static int getParentIndex(int i) { return (i - 1) / 2; } public String toString() {…} // segue implementazione operazioni } ASD - Heap
algoritmi su heap • operazioni • getMax • insert • deleteMax • altri algoritmi • Array2Heap • conversione di un array in heap • HeapSort • ordinamento di un array sfruttando uno heap ASD - Heap
getMax • il max è contenuto nella cella 0 dell’array • operazione di costo costante O(1) ASD - Heap
insert 1. inserisci elemento alla fine dello heap 2. while (elemento non è radice) and (elemento > genitore(elemento)) 3. scambia elemento con genitore ASD - Heap
insert/2 ASD - Heap
insert/3 Algorithm insert(int k) { storage[size] = k; int i = size++; int j = getParentIndex(i); while(!isRoot(i)&&(storage[i]>storage[j])){ exchange(i, j); i = j; j = getParentIndex(i); } } codice semplificato ASD - Heap
deleteMax • sostituisci primo elemento con ultima foglia ed elimina ultima foglia • p = radice • while (p non è foglia) and (p < un figlio) • scambia p con il suo figlio maggiore ASD - Heap
deleteMax/2 ASD - Heap
deleteMax/3 • conviene fare riferimento all'operazione heapify(i ) • utile in deleteMax ed in altri contesti • rende heap il sottoalbero avente radice nella cella di posto i attraverso una sequenza di scambi fra cella i e il suo figlio maggiore • i due sottoalberi di i sono heap ASD - Heap
heapify Algorithm heapify(int i) { if(isLeaf(i)) return; j = getMaxChildIndex(i); if(storage[i] < storage[j]) { exchange(i, j); heapify(j); } } ASD - Heap
heapify/2 public void delMax() { if(!isEmpty()) { storage[0] = storage[--size]; heapify(0); } } ASD - Heap
costi • proporziali all’altezza dello heap (lg n ) • sia per l’inserimento sia per la cancellazione ASD - Heap
heap e code di priorità • una coda di priorità è un tipo astratto con le seguenti operazioni • enqueue, inserimento in coda • dequeue, estrazione dalla coda dell’elemento avente priorità max • la priorità è in genere espressa da un intero • gli heap sono strutture di dati eccellenti per l’implementazione di code di priorità ASD - Heap
altre operazioni su heap • Array2Heap • dato un array di interi costruisce uno heap con quegli interi • HeapSort • dato un array di interi ordina l’array in senso crescente ASD - Heap
Array2Heap • dato un array arr, lo trasforma in un array che rappresenta uno heap attraverso una opportuna permutazione degli elementi • semplice algoritmo for(i = 1; i < arr.length; i++) insert(arr[i]); • costo (sfruttando l’approssimazione di Stirling del fattoriale): ASD - Heap
Array2Heap/2 • l’algoritmo di Floyd è invece basato sull’idea di applicare l’operazione heapify ad alberi binari in cui i figli della radice sono radici di heap • vengono progressivamente “resi heap” i sottoalberi aventi la radice nel penultimo livello, quindi quelli con radice nel terz’ultimo livello ecc. • strategia bottom-up ASD - Heap
66 0 1 2 3 4 5 6 7 8 9 10 11 12 5 4 66 5 4 67 23 64 45 21 89 68 67 39 33 67 23 64 45 21 89 68 67 39 33 66 5 4 67 23 64 45 21 89 68 67 39 33 algoritmo di Floyd ASD - Heap
66 66 66 66 66 89 89 5 5 5 64 64 4 64 4 67 67 67 89 89 68 68 68 68 68 39 64 39 39 64 45 45 45 45 45 21 21 21 21 21 5 89 67 5 67 23 23 23 23 23 67 67 67 67 67 4 39 4 39 4 33 33 33 33 33 algoritmo di Floyd/2 ASD - Heap
89 0 1 2 3 4 5 6 7 8 9 10 11 12 68 64 89 68 64 67 67 39 45 21 5 23 66 4 33 67 67 39 45 21 5 23 66 4 33 algoritmo di Floyd/3 ASD - Heap
implementazione in Java protected Heap(int[] data) {// nuovo costruttore storage = data; size = data.length; for(int i = getParentIndex(size-1); i >= 0; i--) heapify(i); } public static Heap array2heap(int[] data) { return new Heap(data); } ASD - Heap
analisi algoritmo di Floyd • caso peggiore: ogni chiamata di heapify fa il max numero di scambi • supp. heap con n = 2k -1 nodi (albero binario completo di altezza k ) • nel penultimo livello ci sono (n +1)/4 nodi • nel terzultimo (n +1)/8 e così via ASD - Heap
analisi algoritmo di Floyd/2 • una chiamata di heapify su un nodo a livello i provoca al più k – i scambi (op. dominanti) • uno scambio sul penultimo livello, due sul terzultimo ecc. # max di scambi = (# nodi a livello k -1)·1 + (# nodi a livello k -2)·2 + … + (# nodi a livello 2) ·(lg(n +1)-1) + (# nodi a livello 1) ·lg(n +1) = ASD - Heap
analisi algoritmo di Floyd/3 considerato che ne segue che # max di scambi = O(n ) ASD - Heap
applicazioni dell’algoritmo di Floyd • realizzazioni di operazioni non-standard • eliminazione di una chiave qualunque • es.: kill di un processo dato il suo PID • O(n ) per trovare la chiave, O(1) per eliminarla, O(n ) per ripristinare la condizione di heap con l’algoritmo di Floyd • ordinamento di un array • HeapSort ASD - Heap
HeapSort • algoritmo per l’ordinamento di un array arr basato su uno heap Algorithm HeapSort(array arr) { heap = Array2Heap(arr); for(i = n – 1; i >= 0; i--) { max = heap.getMax(); heap.delMax(); arr[i] = max; } } ASD - Heap
HeapSort in Java public static void heapSort(int[] data) { Heap aHeap = array2heap(data); for(int i = aHeap.size - 1; i > 0; i--) { aHeap.exchange(0, i); aHeap.size--; aHeap.heapify(0); } } ASD - Heap
aspetti pratici • codice della classe Heap • esercizio: costruire una classe MinHeap, estendendo Heap opportunamente ASD - Heap