Alberi ( GT. 7 ) Albero definizioni Albero ADT (Abstract Data Type) Algoritmi di base su alberi Alberi binari Strutture dati per rappresentare alberi Implementazione AlberoBinario 1 Alberi (GT. 7) In informatica, un albero è un modello astratto con cui viene rappresentata una struttura gerarchica Albero: insieme di nodi (contenenti informazione) che sono in relazione padre-figlio un albero non vuoto, contiene un nodo speciale che non ha padre, detto root tutti i nodi diversi dalla radice hanno un solo padre ogni nodo con padre p, è figlio di p Albero ordinato: esiste una relazione d’ordine tra i figli di ogni nodo 2 1 Alberi (GT. 7) Struttura dati non lineare: una relazione tra elementi più ricca della semplice relazione lineare “prima” e “dopo” o “precede” e “segue” (stack, coda, lista) La relazione tra gli elementi di un albero è gerarchica: “padre”, “figlio”, “ascendenti”, “discendenti” Computers”R”Us Sales US Manufacturing International Europe Laptops Asia R&D Desktops Canada 3 Tree - terminologia di base (1) Root : nodo senza padre (A) Internal node: node nodo con almeno un figlio (A, B, C, F) External node ( leaf ): nodo senza figli (E, I, J, K, G, H, D) Ancestors di un nodo : nodo, padre, nonno, bisnonno, etc. A B E C F G D H subtree I J K 4 2 Tree - terminologia di base (2) Depth di un nodo: numero di ascendenti (escluso se stesso) Height di un albero: profondità massima dei nodi esterni Descendant di un nodo: nodo, figlio, nipote, pronipote, etc. Subtree: Subtree un albero formato da un nodo e dai suoi discendenti A B E C F G D H subtree I J K 5 Tree – ADT (1) L’ ADT tree memorizza elementi in posizioni, le posizioni in un albero sono rappresentate da nodi Metodi generici: integer size() boolean isEmpty() Iterator iterator() Iterable positions() Metodi di navigazione: position root() position parent (p) positionIterator children (p) 6 3 Tree – ADT (2) Metodi di interrogazione: boolean isInternal(p) boolean isExternal(p) boolean isRoot(p) Metodi di aggiornamento: object replace (p, o) N.B. La specifica in pseudo-codice degli algoritmi sugli alberi fa riferimento alla definizione di tree ADT N.B. Metodi di aggiornamento aggiuntivi potranno essere definiti dalle strutture dati che implementano l’ADT Tree 7 Tree – Interface (§ 7.1.3) (1) public interface Tree<E> { public int size(); /** Returns the number of nodes in the tree. */ public boolean isEmpty(); /** Returns whether the tree is empty. */ public Iterator<E> iterator(); /** Return an iterator of the elements stored in the tree. */ public Iterable<Position<E>> positions(); /** Returns an iterable collection of the nodes stored in the tree. */ /** Replaces the element stored at a given node. */ public E replace ( Position<E> v, E e) throws InvalidPositionException; /** Returns the root of the tree. */ public Position<E> root() throws EmptyTreeException; /** Returns the parent of a given node. */ public Position<E> parent( Position<E> v) throws InvalidPositionException, BoundaryViolationException; 8 4 Tree – Interface (§ 7.1.3) (2) /** Returns an iterable collection of the children of a given node. */ public Iterable<Position<E>> children( Position<E> v ) throws InvalidPositionException; /** Returns whether a given node is internal. */ public boolean isInternal( Position<E> v) throws InvalidPositionException; /** Returns whether a given node is external. */ public boolean isExternal( Position<E> v) throws InvalidPositionException; /** Returns whether a given node is the root of the tree. */ public boolean isRoot( Position<E> v) throws InvalidPositionException; } N.B. La specifica in Java degli algoritmi sugli alberi fa riferimento alla definizione di Tree Interface 9 Linked Structure for General Tree (§ 7.1.3) Oggetto Posizione associato ad un nodo Lista dei figli di un nodo 10 5 Alberi – Algoritmi di base (§ 7.2) Profondità (depth) di un nodo v è il numero di Running time ascendenti di v ( escluso v stesso ) Algoritmo depth(T,v) O(d v ) if T.isRoot(v) then return 0 else O(n) return 1 + depth(T, T.parent(v)) public static <E> int depth( Tree<E> T, Position<E> v) { if (T.isRoot(v) ) return 0; else return 1 + depth(T, T.parent(v) ); } profondità massima nel caso più sfavorevole è : n −1 11 Alberi – Algoritmi di base (§ 7.2) Altezza ( height ) di un nodo v è zero se v è un nodo esterno altrimenti, è 1 + l’altezza del più alto dei figli di v Algoritmo height_1 (T) In pseudocodice : h=0 l’altezza è uguale for ogni v in T do alla profondità if T.isExternal(v) then h = max ( h, depth(T,v ) ) del più profondo dei nodi esterni return h 12 6 Alberi – Algoritmi di base (§ 7.2) Altezza (height) di un nodo v public static <E> int height_1 (Tree<E> T) { int h = 0; Codice Java in base all’ interface Tree Iterable pos = T.positions(); for ( Position<E> v : pos ) { if ( T.isExternal(v) ) Elevata complessità h = Math.max( h, depth(T,v) ); } return h } Caso più sfavorevole O(n + ∑v∈E (1 + d v )) O(n 2 ) 13 Alberi– Algoritmi di base (§ 7.2) Altezza algoritmo 2 In pseudocodice : l’algoritmo segue la Algoritmo height_2 (T, v ) definizione ricorsiva if T.isExternal(v) then return 0 else h=0 for ogni w in T.children(v) do h = max ( h, height_2 (T,w ) ) return 1 + h 14 7 Alberi – Algoritmi di base (§ 7.2) Codice Java in base all’ interface Tree Altezza algoritmo 2 public static <E> int height_2 (Tree<E> T, Position<E> v ) { if ( T.isExternal(v) ) return 0; else { int h = 0; Iterable ch = T.children(v); for ( Position<E> w : ch ) h = Math.max( h, heigt_2 ( T, w ); return 1 + h; } } 15 Alberi – Algoritmi di base (§ 7.2) Altezza - algoritmo 2 - analisi complessità : ¾ L’algoritmo è basato sulla def. ricorsiva di altezza : viene applicato una sola volta su ogni nodo dell’albero T ¾ per ciascun nodo, il calcolo l’iterazione su tutti i children(v) richiede O ( cv ) , ¾ il ciclo while compie con cv cv numero dei figli del nodo v iterazioni, percio’ per ogni nodo l’algoritmo spende ¾ poiché è : ∑v∈T cv = n − 1 ¾ il costo complessivo è : O(1 + cv ) Ogni nodo è figlio di un altro nodo tranne la radice O(∑v∈T (1 + cv )) = O(n) 16 8 Attraversamento – Preordine (§ 7.2.2) Un attraversamento di un albero T è un modo sistematico per accedere, o visitare, tutti i nodi di T Alla visita di un nodo è associata una specifica azione dipendente dalla particolare applicazione Nell’attraversamento in preordine un nodo viene visitato prima dei suoi discendenti Algorithm preorder(T, v) visit(v) for each child w of v in T do preorder (T, w) 17 Visita in preordine - esempio Paper Title Abstr p. 1 1.1 1.2 p. 3 p. 2 2.1 2.2 2.3 3.1 Refer. 3.2 Nel preordine prima viene visitata la radice poi, nell’ordine, i diversi sottoalberi 18 9 Preodine – analisi complessità ¾ L’algoritmo rappresenta una strategia efficiente per visitare in modo sistematico tutti i nodi di un albero ¾ Per ciascun nodo v dell’albero, la parte non ricorsiva dell’algoritmo di attraversamento richiede : O(1 + cv ) ¾ perciò il tempo complessivo risulta essere : O(∑v∈T (1 + cv )) = O(n) dato che : ∑ v∈T cv = n − 1 19 Preordine – esempio in Java Esempio: metodo in codice Java per la stampa in preordine degli elementi associati ai nodi di un albero in Java public static E String toStringPreorderPrint (Tree<E> T, Position<E> v ) { String s = v.element().toString(); Iterable ch_set = T.children(v); for ( Position<E> w : ch_set ) s = s + toStringPreorderPrint(T, w ); return s } 20 10 Attraversamento - Postordine Nell’attraversamento in postordine, postordine un nodo viene visitato dopo i suoi discendenti: Algorithm postOrder( T, v) for each child w of v do postOrder (T, w) visit(v) 21 Postordine - esempio Applicazione: calcolare lo spazio usato dai file in una directory e dalle sue sotto_directory Il problema può essere risolto in modo bottom-up con un attraversamento in postordine: 9 cs16/ 3 8 7 homeworks/ todo.txt 1K programs/ 1 2 h1c.doc 3K h1nc.doc 2K 4 DDR.java 10K 5 Stocks.java 25K 6 Robot.java 20K 22 11 Altri tipi di attraversamento Postordine e Preordine seguono una strategia di tipo DFS (depthfirst-search ) (prima in profondità) E’ possibile anche seguire una strategia di tipo BFS (breadthfirst-search) : visita per livelli successivi a partire dalla root è possibile un algoritmo iterativo che utilizza un ADT Coda Esercizio: realizzare l’algoritmo in pseudo codice e in Java 1.1 2.1 A 2.3 2.2 B C 3.1 3.2 E F 3.4 G 3.5 H D 3.6 I 23 12