Árvores Binárias de Pesquisa (revisões) Algoritmos e Estruturas de Dados II Licenciatura em Engenharia Informática e Computação www.fe.up.pt/ rcamacho/cadeiras/aed2 LIACC/FEUP Universidade do Porto rcamacho@fe.up.pt Fevereiro 2005
Árvores Conjunto de nós e conjunto de arestas que ligam pares de nós Um nó é a raiz Com excepção da raiz, todo o nó está ligado por uma aresta a 1 e 1 só nó (o pai) Há um caminho único da raiz a cada nó; o tamanho do caminho para um nó é o número de arestas a percorrer Nós sem descendentes: folhas Árvores Binárias de Pesquisa Sumário Definição. Árvore binária pesquisa Interface Nó de árvore Implementação Iteradores de árvore Visita em pré-ordem, pós-ordem, in-ordem
Interface de árvore de pesquisa // SearchTree interface // // ************PUBLIC OPERATIONS*************** // void insert( x) Insert x // void remove( x) Remove x // void removemin() Remove smallest item // Comparable find( x) Return item that matches x // Comparable findmin() Return smallest item // Comparable findmax() Return largest item // boolean isempty() Return true if empty; else false // void makeempty() Remove all items // void printtree() Print tree in sorted order // ************ERRORS************************** // Most routines throw ItemNotFound on various degenerate conditions // insert throws DuplicateItem if item is already in the tree Árvores Binárias de pesquisa Pesquisa em elementos ordenados: pode ser feita em O(log n)... sem inserção ou remoção de elementos Manter o tempo de acesso logarítmico com inserção e remoção estrutura em árvore binária mais operações do que árvore básica: pesquisar, inserir, remover Objectos nos nós devem ser comparáveis interface Comparable: objectos de classes que a implementam podem ser comparados
Nó de árvore binária class BinaryNode{ // Friendly data accessible by other package routines Comparable element; // The data in the node BinaryNode left; // Left child BinaryNode right; // Right child BinaryNode(Comparable theelement){ this(theelement, null, null); BinaryNode(Comparable theelement, BinaryNode lt, BinaryNode rt){ element = theelement; left = lt; right = rt; Interface de árvore de pesquisa public interface SearchTree{ void insert(comparable x) throws DuplicateItem; void remove(comparable x) throws ItemNotFound; void removemin() throws ItemNotFound; Comparable findmin() throws ItemNotFound; Comparable findmax() throws ItemNotFound; Comparable find(comparable x) throws ItemNotFound; void makeempty(); boolean isempty(); void printtree();
Implementação de árvore binária public void removemin() throws ItemNotFound{ root = removemin(root); public Comparable findmin() throws ItemNotFound{ return findmin(root).element; public Comparable findmax() throws ItemNotFound{ return findmax(root).element; public Comparable find(comparable x) throws ItemNotFound{ return find(x, root).element; public void makeempty(){ root = null; Implementação de árvore binária public class BinarySearchTree implements SearchTree{ /** The tree root. */ protected BinaryNode root; public BinarySearchTree(){ root = null; public void insert(comparable x) throws DuplicateItem{ root = insert(x, root); public void remove(comparable x) throws ItemNotFound{ root = remove(x, root);
Implementação de árvore binária protected BinaryNode remove(comparable x, BinaryNode t) throws ItemNotFound{ if(t == null) throw new ItemNotFound( SearchTree remove ); if(x.compares(t.element) < 0) t.left = remove(x, t.left); else if(x.compares(t.element) > 0) t.right = remove(x, t.right); else if(t.left!= null && t.right!= null){ // Two children t.element = findmin(t.right).element; t.right = removemin(t.right); else t = (t.left!= null)? t.left : t.right; return t; Implementação de árvore binária public boolean isempty(){ return root == null; public void printtree(){ if(root == null) System.out.println( Empty tree ); else printtree(root); protected BinaryNode insert(comparable x, BinaryNode t) throws DuplicateItem{ if(t == null) t = new BinaryNode(x, null, null); else if(x.compares(t.element) < 0) t.left = insert(x, t.left); else if(x.compares(t.element) > 0) t.right = insert(x, t.right); else throw new DuplicateItem( SearchTree insert ); return t;
Implementação de árvore binária protected BinaryNode findmax(binarynode t) throws ItemNotFound{ if(t == null) throw new ItemNotFound( SearchTree findmax ); while(t.right!= null) t = t.right; return t; protected BinaryNode find(comparable x, BinaryNode t) throws ItemNotFound{ while(t!= null) if(x.compares(t.element) < 0) t = t.left; else if(x.compares(t.element) > 0) t = t.right; else return t; // Match throw new ItemNotFound( SearchTree find ); Implementação de árvore binária protected BinaryNode removemin(binarynode t) throws ItemNotFound{ if(t == null) throw new ItemNotFound( SearchTree removemin ); if(t.left!= null) t.left = removemin(t.left); else t = t.right; return t; protected BinaryNode findmin(binarynode t) throws ItemNotFound{ if(t == null) throw new ItemNotFound( SearchTree findmin ); while(t.left!= null) t = t.left; return t;
Iterador em árvore binária Operação: percorrer todos os nós da árvore, por ordem escolhida pré-ordem: um nó é visitado, seguindo-se a visita dos seus filhos pós-ordem: nó é visitado após a visita dos seus filhos in-ordem: nó é visitado entre as visitas do filho esquerdo e do filho direito Visita da árvore implementada por uma aplicação a visita pode exprimir-se recursivamente de forma muito simples o contexto de execução do programa (na stack) mantém a informação necessária para realizar a visita na ordem pretendida Visita da árvore encapsulada na classe de um iterador contexto tem de ser mantido pelo iterador iterador gere uma pilha para manter registo do estado da visita Implementação de árvore binária protected void printtree(binarynode t){ if(t!= null){ printtree(t.left); System.out.println(t.element.toString()); printtree(t.right);
Implementação de iterador de árvore final public Object retrieve() throws ItemNotFound{ if(current == null) throw new ItemNotFound( TreeIterator retrieve ); return current.element; abstract public void advance() throws ItemNotFound; Implementação de iterador de árvore abstract public class TreeIterator{ protected BinarySearchTree t; // Tree protected BinaryNode current; // Current position public TreeIterator(BinarySearchTree thetree){ t = thetree; current = null; abstract public void first(); final public boolean isvalid(){ return current!= null;
Iterador em pré-ordem public class PreOrder extends TreeIterator{ private Stack s; // Stack of TreeNode objects public PreOrder(BinarySearchTree thetree){ super(thetree); s = new StackAr(); s.push(t.root); public void first(){ s.makeempty(); if(t.root!= null) s.push(t.root); try{ advance(); catch(itemnotfound e){ // Empty tree Nó na pilha do iterador package DataStructures; // An internal class for tree iterators class StNode{ BinaryNode node; int timespopped; StNode(BinaryNode n){ node = n; timespopped = 0;
Iterador em pós-ordem public class PostOrder extends TreeIterator{ protected Stack s; // The stack of StNode objects public PostOrder(BinarySearchTree thetree){ super(thetree); s = new StackAr(); s.push(new StNode(t.root)); public void first(){ s.makeempty(); if(t.root!= null) s.push(new StNode(t.root)); try{ advance(); catch(itemnotfound e){ // Empty tree Iterador em pré-ordem public void advance() throws ItemNotFound{ if(s.isempty()){ if(current == null) throw new ItemNotFound( PreOrder Advance ); current = null; return; try{ current = (BinaryNode) s.topandpop(); catch(underflow e){ return; // Cannot happen if(current.right!= null) s.push(current.right); if(current.left!= null) s.push(current.left);
Iterador em in-ordem public class InOrder extends PostOrder{ public InOrder( BinarySearchTree thetree){ super(thetree); public void advance() throws ItemNotFound{ if(s.isempty()){ if(current == null) throw new ItemNotFound( InOrder Advance ); current = null; return; StNode cnode;... for(; ;){ try{ cnode = (StNode) s.topandpop(); catch(underflow e){ return; if(++cnode.timespopped == 2){ current = cnode.node; if(cnode.node.right!= null) s.push(new StNode(cnode.node.right)); return; // First time through s.push(cnode); if(cnode.node.left!= null) s.push(new StNode(cnode.node.left)); Iterador em pós-ordem public void advance() throws ItemNotFound{ if(s.isempty()){ if(current == null) throw new ItemNotFound( PostOrder Advance ); current = null; return; StNode cnode;... for(; ;){ try{ cnode = (StNode) s.topandpop(); catch(underflow e){ return; if(++cnode.timespopped == 3){ current = cnode.node; return; s.push(cnode); if(cnode.timespopped == 1){ if(cnode.node.left!= null) s.push(new StNode(cnode.node.left)); else // cnode.timespopped == 2 { if(cnode.node.right!= null) s.push(new StNode(cnode.node.right));
Iterador em ordem de nível public void advance() throws ItemNotFound{ if(q.isempty()){ if(current == null) throw new ItemNotFound( LevelOrder advance ); current = null; return; try{ current = (BinaryNode) q.dequeue(); catch(underflow E){ return; // Cannot happen if(current.left!= null) q.enqueue(current.left); if(current.right!= null) q.enqueue(current.right); Iterador em ordem de nível public class LevelOrder extends TreeIterator{ private Queue q; // Queue of TreeNode objects public LevelOrder(BinarySearchTree thetree){ super(thetree); q = new QueueAr(); q.enqueue(t.root); public void first(){ q.makeempty(); if(t.root!= null) q.enqueue(t.root); try{ advance(); catch(itemnotfound e){ // Empty tree
Testar iterador de árvore public static void main(string[ ] args){ BinarySearchTree t = new BinarySearchTree(); testitr( PreOrder, new PreOrder(t)); try{ t.insert(new MyInteger(4)); t.insert(new MyInteger(2)); t.insert(new MyInteger(6)); t.insert(new MyInteger(1)); t.insert(new MyInteger(3)); t.insert(new MyInteger(5)); t.insert(new MyInteger(7)); catch(exception e){ testitr( Preorder, new PreOrder(t)); testitr( Postorder, new PostOrder(t)); testitr( Inorder, new InOrder(t)); testitr( Level order, new LevelOrder(t)); Testar o iterador public static void testitr(string type, TreeIterator itr){ try{ System.out.print(type + : ); for(itr.first(); itr.isvalid(); itr.advance()) System.out.print( + itr.retrieve()); System.out.println(); itr.advance(); catch(itemnotfound E){ System.out.println(E + (as expected) );