alberi tipo astratto, implementazione, algoritmi argomenti tipo astratto albero definizione implementazione in Java algoritmi di visita alberi binari implementazione di alberi binari in Java ASD - Alberi 2 tipo di dato astratto albero insieme vuoto di nodi oppure costituito da una radice R e da 0 o più alberi (sottoalberi) la radice di ogni sottoalbero è collegata a R da un arco R es.: radice R con n sottoalberi T1 ASD - Alberi T2 Tn 3 terminologia genitore, figlio, fratello radice concetti intuitivi nodo interno nodo foglia se ha zero figli interno se ha almeno un figlio ASD - Alberi foglia 4 terminologia/2 livello di un nodo lunghezza (n.ro nodi) percorso radice-nodo ramo livello radice = 1 percorso radice-foglia altezza albero altezza = 3 lunghezza (n.ro nodi) ramo più lungo ASD - Alberi 5 alberi? ASD - Alberi 6 esempi di alberi alberi genealogici gerarchie di ereditarietà classificazioni di specie animali organizzazione del territorio ad es., in Java continente, nazione, regione, provincia ecc (alcuni) organigrammi file system domini Internet ASD - Alberi 7 rappresentazione di alberi con liste collegate livello di C = 3 R B A Primo figlio di R C Fratello di A Elemento Riferimento al prossimo fratello Riferimento al primo figlio ASD - Alberi 8 operazioni sugli alberi operazioni più importanti element(v): restituisce l’elemento memorizzato nel nodo v root(): restituisce la radice dell’albero parent(v): restituisce il genitore del nodo v children(v): restituisce i figli di v isLeaf(v): restituisce true se v è una foglia isRoot(v): restituisce true se v è la radice ASD - Alberi 9 operazioni sugli alberi Altre operazioni livello di un nodo altezza dell’albero # nodi # foglie arità max # di figli di un nodo dell’albero isEmpty true se l’albero ha zero nodi ASD - Alberi 10 rappresentazione dei nodi in Java nodi class TreeNode { Object element; TreeNode firstChild; TreeNode nextSibling; TreeNode parent; } ASD - Alberi 11 tipo astratto albero in Java public interface Tree { Object element(TreeNode v); TreeNode root(); TreeNode parent(TreeNode v); ListIterator children(TreeNode v); boolean isLeaf(TreeNode v); boolean isRoot(TreeNode v); } ASD - Alberi 12 algoritmi su alberi livello di un nodo public int level(TreeNode v) { if(this.isRoot(v)) return 1; else return 1 + level(this.parent(v)); } costo proporzionale all’altezza: O(h ) ASD - Alberi 13 algoritmi su alberi/2 altezza di un (sotto)albero costo proporzionale al numero di nodi: (n ) viene esaminato ogni nodo ciascun nodo viene esaminato una sola volta int height(v) { int h=0, hmax=0; if(v == null) return 0; if(isLeaf(v)) return 1; TreeNode w = v.firstChild; hmax = height(w); while(w.nextSibling != null) { w = w.nextSibling; h = height(w); if(h > hmax) hmax = h; } return 1 + hmax; } ASD - Alberi 14 algoritmi su alberi/3 visita (o attraversamento) di un albero in profondità (depth-first search, a scandaglio): DFS vengono visitati i rami, uno dopo l’altro tre varianti in ampiezza (breadth-first search, a ventaglio): BFS a livelli, partendo dalla radice ASD - Alberi 15 visite in profondità/preordine in preordine (preorder, o ordine anticipato) dato un nodo v visita v visita i sotto-alberi aventi come radice i figli di v, da sinistra verso destra void treePreorder(root) { if(root == null) return; <visita root> r = root.firstChild while (r != null) { treePreorder(r); r = r.nextSibling; } ASD - Alberi } 16 visite in profondità/inordine in ordine simmetrico (inorder) dato un nodo v con k sotto-alberi visita il primo sotto-albero (radice v.firstChild) visita v visita gli altri k-1 sotto-alberi void treeInorder(root) { if(root == null) return; r = root.firstChild; treeInorder(r); <visita root> r = r.nextSibling; while (r != null) { treeInorder(r); r = r.nextSibling; } } ASD - Alberi 17 visite in profondità/postordine in postordine (postorder, o ordine posticipato) dato un nodo v visita i sotto-alberi aventi come radice i figli di v, da sinistra verso destra visita v void treePostorder(root) { if(root == null) return; r = root.firstChild while (r != null) { treePostorder(r); r = r.nextSibling; } <visita root> ASD - Alberi } 18 visite in profondità 2 1 2 3 4 1 5 6 preordine 7 7 4 3 1 6 5 inordine ASD - Alberi 7 3 2 6 4 5 postordine 19 visita in ampiezza breadth-first search (BFS), usa una coda dato un nodo v void bfs(v) { if(v == null) return; queue.enqueue(v); while (!queue.isEmpty()) { v = queue.dequeue(); v.visit(); TreeNode w = v.firstChild; while(w != null) { queue.enqueue(w); w = w.nextSibling; } } ASD - Alberi } 20 visita in ampiezza 1 2 3 4 5 6 7 BFS ASD - Alberi 21 alberi binari un albero si dice binario se ogni nodo può avere al più 2 figli la rappresentazione si semplifica public class BinaryNode { protected Object element; protected BinaryNode leftChild; protected BinaryNode rightChild; } ASD - Alberi 22 ADT albero binario in Java public interface BinaryTree { Object element(BinaryNode v); BinaryNode root(); BinaryNode parent(BinaryNode v); BinaryNode leftChild(BinaryNode v); BinaryNode rightChild(BinaryNode v); boolean isLeaf(BinaryNode v); boolean isRoot(BinaryNode v); } ASD - Alberi 23 alberi binari/visita in preordine void treePreorder(BinaryNode v) { if(v == null) return; <visita v> treePreorder(leftChild(v)); treePreorder(rightChild(v)); } ASD - Alberi 24 alberi binari/visita inordine void treeInorder(BinaryNode v) { if(v == null) return; treeInorder(leftChild(v)); <visita v> treeInorder(rightChild(v)); } ASD - Alberi 25 alberi binari/visita in postordine void treePostorder(BinaryNode v) { if(v == null) return; treePostorder(leftChild(v)); treePostorder(rightChild(v)); <visita v> } ASD - Alberi 26 alberi binari/visita in ampiezza void bfs(v) { TreeNode p = v; queue.enqueue(p); while (!queue.isEmpty()) { p = (BSTNode) queue.dequeue(); p.visit(); if (p.leftChild != null) queue.enqueue(p.leftChild); if (p.rightChild != null) queue.enqueue(p.rightChild); } } ASD - Alberi 27 strutture dati per alberi binari vettori rappresentazioni collegate esercizi: implementare l’interfaccia BinaryTree usando una rappresentazione collegata scrivere un programma che legga gli elementi (stringhe) di un albero binario e li stampi effettuando una visita in preordine ASD - Alberi 28 uso di vettori ogni nodo v è memorizzato in posizione p(v) 2 4 se v è la radice allora p(v)=1 (indice 0 in Java, C, C++) se v è il figlio sinistro di u allora p(v)=2p(u) se v è il figlio destro di u allora 1 p(v)=2p(u)+1 2 1 3 4 3 6 7 6 7 ASD - Alberi 29 uso di vettori/2 implementazione statica: è necessaria una stima del numero massimo di nodi dell’albero può portare a spreco di risorse nel caso peggiore, un albero con n nodi richiede un vettore con 2n-1 elementi (se l’albero degenera in una catena) ASD - Alberi 30 uso di vettori/3 in Java: si possono usare le classi Vector (sincronizzata) o ArrayList (non sincronizzata) Vector e ArrayList gestiscono anche il ridimensionamento quando il numero di elementi cresce oltre la capacità corrente ciò porta a ritardi (per gestire l’allocazione di nuova memoria) esercizio: scrivere una classe che implementi l’interfaccia BinaryTree usando ArrayList o Vector ASD - Alberi 31 rappresentazione collegata public class LinkedBinaryTree implements BinaryTree { private BinaryNode root; /* Rif. alla radice*/ private int size; public LinkedBinaryTree() { root = new BinaryTreeNode(null, null, null); size = 0; } /* Metodi */ } /* Fine della classe */ ASD - Alberi 32