1.09k likes | 1.22k Views
Árvores. Definição. Definição (Árvore) Uma árvore T é um conjunto finito e não vazio de nós , com as seguintes propriedades: Um certo nó do conjunto, r , é chamado de raiz da árvore; e
E N D
Definição • Definição (Árvore) Uma árvoreT é um conjunto finito e não vazio de nós, com as seguintes propriedades: • Um certo nó do conjunto, r, é chamado de raiz da árvore; e • Os demais nós são repartidos em sub conjuntos, T1, T2, ..., Tn , cada um dos quais sendo uma árvore. • É usual adotar para a árvore T a notação.
Nomenclatura • Seja uma árvore com n 0 • Grau de um nó é o número de sub-árvores do nó • Folha é um nó de grau zero • As raízes ri das sub-árvores Ti são filhas de r • A raiz r da árvore T é pai das raízes ri • Raízes ri e rj de árvores distintas Ti e Tj são irmãs
Nomenclatura • Nível ou profundidade de um nó ri de uma árvore T é o comprimento do caminho entre a raiz e o nó ri • A raiz está no nível zero e seus filhos estão no nível 1 (Preiss) • A raiz está no nível 1 e seus filhos estão no nível 2 (Horowitz) • Altura de um nó é o caminho mais longo do nó até uma folha • Altura de uma árvore é a altura do nó raiz • O pai de um nó é seu ancestral e o pai de seu pai também • O filho de um nó é seu descendente e o filho de seu filho também • Ordem de um nó é o grau do nó • Ordem de uma árvore é a ordem de seu nó de maior ordem
Nomenclatura Níveis em versão Horowitz
Representação de árvores por parênteses • A árvore acima teria a seguinte representação usando parênteses: • (A(B(E(K, L), F)) , (C (G)), (D(H(M), I, J))))
Caminho e Comprimento de Caminho • Definição (Caminho e Comprimento de Caminho) Para uma árvore T contendo o conjunto de nós R, um caminho em T é definido como uma seqüência não vazia de nós do caminho
Árvores N-árias • Definição (Árvores N-arias) Uma árvore N-aria T é um conjunto finito de nós com as propriedades: • Ou o conjunto é vazio, T= ; ou • O conjunto consiste em uma raiz, R, e exatamente N árvores N-arias distintas. Os demais nós são repartidos em N0 sub conjuntos, T0,T1 , ..., TN-1 , cada qual sendo uma árvore N-aria tal que
Árvore Binária • Definição (Árvore Binária) Uma árvorebinária T é um conjunto finito de nós com as propriedades: • Ou o conjunto é vazio, T = ; ou • O conjunto consiste em uma raiz, r, e exatamente duas árvores binárias distintas T L e TR . A árvore TL é chamada árvore da esquerda de T, e a árvore TR é chamada árvore da direita de T.
Travessia ou Visitação de Árvores • Existem dois métodos de visitação sistemática a todos os nós de uma árvore: • Travessia em largura ou breadth-first traversal (BFT) • Travessia em profundidade ou depth-first traversal (DFT)
Backtracking • Backtracking é um esquema de solução de uma série de sub problemas cada um dos quais podendo ter múltiplas possíveis soluções e aonde a solução escolhida para um subproblema pode afetar as possíveis soluções dos subproblemas posteriores • Para resolver o problema como um todo encontra-se a solução do primeiro sub problema e busca-se recursivamente resolver os outros sub problemas com base na primeira solução • Se isto não for possível ou caso se deseje obter todas as possíveis soluções faz-se o backtrack e tenta-se a próxima solução possível para o primeiro sub problema e assim por diante • Backtracking termina quando não mais existem soluções para o primeiro sub problema.
DFT e BFT • depth-first search ou busca em profundidade: Algoritmo de busca em grafos que estende o caminho corrente tanto quanto possível, antes de executar backtracking, até o último ponto aonde houve escolha e tentar outro caminho alternativo • breadth first search ou busca em largura: Algoritmo de busca em grafos que tenta todas as possíveis extensões de um passo antes de tentar extensões maiores • Isto obriga que se mantenham em memória todos os caminhos correntes, ou, pelo menos, seus pontos terminais.
BFT (Breadth-First Traversal) • Enquanto a travessia em profundidade (DFT) é definida recursivamente a travessia em largura é melhor compreendida como uma travessia não recursiva • A travessia BFT de uma árvore visita os nós em ordem de sua profundidade na árvore • BFT primeiro visita todos os nós à profundidade zero (i. e. a raiz), então todos os nós à profundidade um e assim por diante • Em cada nível os nós são visitados da esquerda para a direita
Implementação de árvores binárias por “arrays” • Se um nó está na posição i, seu pai está na posição i/2 se i 0 (caso o nó inicial seja 0 em vez de 1 o valor serái/2 - 1) • O filho esquerdo (mais velho) de i está na posição: • 2 i se 2*i n (caso o nó inicial seja 0 em vez de 1 o valor será 2*i+1) • Caso contrário este filho não existe • O filho direito (mais novo) de i está na posição: • 2*i + 1 se 2*i + 1n (caso o nó inicial seja 0 em vez de 1 o valor será 2*i+2) • Caso contrário este filho não existe
Implementação de árvores binárias por encadeamento • Os nós das árvores binárias podem ser representados da forma
Caminhamento ou percurso sobre árvores binárias • Uma seqüência de nós que contenha todos os nós de uma árvore binária, sem repetições, produz uma relação de ordem total para seus nós que é chamado de caminhamento ou percurso sobre a árvore
Caminhamento ou percurso sobre árvores binárias • São possíveis as seguintes seqüências: • ECD - ordem infixa • EDC - ordem pós-fixa • CED - ordem pré-fixa • CDE (pré-fixa) • DCE descartadas (infixa) • DEC (pós-fixa) • A ordem infixa é a ordem de percurso na qual percorre-se a sub árvore da esquerda, “visita-se” a raiz e percorre-se a sub árvore da direita. • A ordem pós-fixa é aquela na qual percorre-se a sub árvore da esquerda, a sub árvore da direita e “visita-se” a raiz. • A ordem pré-fixa é aquela na qual “visita-se” a raiz, percorre-se a sub árvore da esquerda e a sub árvore da direita.
Caminhamento ou percurso sobre árvores binárias • Percurso ou notação pré-fixa: ABDHIECFG • Percurso ou notação infixa: HDIBEAFCG • Percurso ou notação pós-fixa: HIDEBFGCA
Notação Decimal de Dewey • Os nós de uma árvore binária podem ser identificados por uma seqüência de zeros e uns em uma notação análoga à notação decimal de Dewey de acordo com as regras que se seguem. • (i) A raiz é representada por “1” • (ii) O filho mais velho do nó “x” é representado por “x0” • (iii) O filho mais novo do nó “x” é representado por “x1”.
Interface Tree //pgm09_01.txt public interface Tree extends Container { Object getKey (); Tree getSubtree (int i); boolean isEmpty (); boolean isLeaf (); int getDegree (); int getHeight (); void depthFirstTraversal (PrePostVisitor visitor); void breadthFirstTraversal (Visitor visitor); }
Métodos da Interface Tree getKey Este método retorna o objeto contido no nó raiz de uma árvore. getSubtree Este método retorna a -iésima sub árvore de uma árvore. isEmpty Este método booleano retorna true se a raiz da árvore for uma árvore vazia, i, e. um nó externo. isLeaf Este método booleano retorna true se a raiz da árvore for um nó folha. getDegree Este método retorna o grau do nó raiz de uma árvore. Por definição, o grau de um nó externo é zero. getHeight Este método retorna a altura de uma árvore. Por definição, a altura de uma árvore vazia é -1. depthFirstTraversal and breadthFirstTraversal Estes métodos são semelhantes ao método accept da classe container. Ambos executam uma travessia. Todos os nós são visitados sistematicamente. O primeiro aceita um PrePostVisitor e o último aceita um Visitor. Quando um nó for visitado os métodos apropriados do visitor são aplicados ao nó.
Método depthFirstTraversal de AbstractTree // pgm09_02.txt public abstract class AbstractTree extends AbstractContainer implements Tree { public void depthFirstTraversal (PrePostVisitor visitor) { if (visitor.isDone ()) return; if (!isEmpty ()) { visitor.preVisit (getKey ()); for (int i = 0; i < getDegree (); ++i) getSubtree (i).depthFirstTraversal (visitor); visitor.postVisit (getKey ()); } } // ... }
Interface PrePostVisitor //pgm09_03.txt public interface PrePostVisitor { void preVisit (Object object); void inVisit (Object object); void postVisit (Object object); boolean isDone (); }
Classe Abstrata AbstractPrePostVisitor //pgm09_04.txt public abstract class AbstractPrePostVisitor implements PrePostVisitor { public void preVisit (Object object) {} public void inVisit (Object object) {} public void postVisit (Object object) {} public boolean isDone () { return false; } }
Classe PreOrder // //pgm09_05.txt public class PreOrder extends AbstractPrePostVisitor { protected Visitor visitor; public PreOrder (Visitor visitor) { this.visitor = visitor; } public void preVisit (Object object) { visitor.visit (object); } public boolean isDone () { return visitor.isDone (); } }
Classe InOrder // //pgm09_06.txt public class InOrder extends AbstractPrePostVisitor { protected Visitor visitor; public InOrder (Visitor visitor) { this.visitor = visitor; } public void inVisit (Object object) { visitor.visit (object); } public boolean isDone () { return visitor.isDone (); } }
Classe PostOrder // //pgm09_07.txt public class PostOrder extends AbstractPrePostVisitor { protected Visitor visitor; public PostOrder (Visitor visitor) { this.visitor = visitor; } public void postVisit (Object object) { visitor.visit (object); } public boolean isDone () { return visitor.isDone (); } }
Exemplo de travessia de Árvores Visitor v = new PrintingVisitor (); Tree t = new SomeTree (); // ... t.depthFirstTraversal (new PreOrder (v)); t.depthFirstTraversal (new InOrder (v)); t.depthFirstTraversal (new PostOrder (v));
Implementação de BFT (1) // pgm09_08.txt public abstract class AbstractTree extends AbstractContainer implements Tree { public void breadthFirstTraversal (Visitor visitor) { Queue queue = new QueueAsLinkedList (); if (!isEmpty ()) queue.enqueue (this); } } }
Implementação de BFT (2) while (!queue.isEmpty () && !visitor.isDone ()) { Tree head = (Tree) queue.dequeue (); visitor.visit (head.getKey ()); for (int i = 0; i < head.getDegree (); ++i) { Tree child = head.getSubtree (i); if (!child.isEmpty ()) queue.enqueue (child); } } } }
Método accept // pgm09_09.txt public abstract class AbstractTree extends AbstractContainer implements Tree { public void accept (Visitor visitor) { depthFirstTraversal (new PreOrder (visitor)); } // ... } • A escolha de ordem pré-fixa foi arbitrária
Exemplo de varredura de Árvore Tree tree = new BinaryTree (); // ... Enumeration e = tree.getEnumeration (); while (e.hasMoreElements ()) { Object obj = e.nextElement (); System.out.println (obj); }
Classe interna TreeEnumeration // pgm09_10.txt public abstract class AbstractTree extends AbstractContainer implements Tree { public Enumeration getEnumeration () { return new TreeEnumeration (); } protected class TreeEnumeration implements Enumeration { protected Stack stack; // ... } // ... }
Construtor de TreeEnumeration // pgm09_11.txt public abstract class AbstractTree extends AbstractContainer implements Tree { protected class TreeEnumeration implements Enumeration { public TreeEnumeration () { stack = new StackAsLinkedList (); if (!isEmpty ()) stack.push (AbstractTree.this); } } // ... } • A escolha da enumeração ser por BFT foi arbitrária
Método hasMoreElements da Classe AbstractTree // pgm09_12.txt public abstract class AbstractTree extends AbstractContainer implements Tree { protected class TreeEnumeration implements Enumeration { public boolean hasMoreElements () { return !stack.isEmpty (); }
Método nextElement da Classe AbstractTree public Object nextElement () { if (stack.isEmpty ()) throw new NoSuchElementException (); Tree top = (Tree) stack.pop (); for (int i = top.getDegree () - 1; i >= 0; --i) { Tree subtree = (Tree) top.getSubtree (i); if (!subtree.isEmpty ()) stack.push (subtree); } return top.getKey (); } } } • O empilhamento foi em ordem inversa para a enumeração ser em ordem direta (BFT)
Classe GeneralTree // //pgm09_13.txt public class GeneralTree extends AbstractTree { protected Object key; protected int degree; protected LinkedList list; // ... }
Métodos Construtor e Purge de GeneralTree // pgm09_14.txt public class GeneralTree extends AbstractTree { protected Object key; protected int degree; protected LinkedList list; public GeneralTree (Object key) { this.key = key; degree = 0; list = new LinkedList (); } public void purge () { list.purge (); degree = 0; } }