número 3

Propaganda
Revisões – Java
Revisões – Complexidade
Árvores Binárias de Pesquisa
(revisões)
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
Algoritmos e Estruturas de Dados II
– Licenciatura em Engenharia Informática e Computação –
www.fe.up.pt/∼rcamacho/cadeiras/AED2
Rui Camacho
LIACC/FEUP Universidade do Porto
[email protected]
Fevereiro 2005
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
Árvores
Conjunto de nós e conjunto de arestas que ligam pares de nós
I Um nó é a raiz
I Com excepção da raiz, todo o nó está ligado por uma aresta a 1 e 1 só nó
(o pai)
I Há um caminho único da raiz a cada nó; o tamanho do caminho para um
nó é o número de arestas a percorrer
I Nós sem descendentes: folhas
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
Árvores Binárias de Pesquisa
Sumário
I
Definição.
I
Árvore binária pesquisa
I
I
I
I
Interface
Nó de árvore
Implementação
Iteradores de árvore
I
Visita em pré-ordem, pós-ordem, in-ordem
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
Árvores Binárias de pesquisa
I
Pesquisa em elementos ordenados: pode ser feita em O(log n)
I
I
Manter o tempo de acesso logarı́tmico com inserção e
remoção
I
I
I
... sem inserção ou remoção de elementos
estrutura em árvore binária
mais operações do que árvore básica: pesquisar, inserir,
remover
Objectos nos nós devem ser comparáveis
I
interface Comparable: objectos de classes que a implementam
podem ser comparados
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
}
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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();
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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);
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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”);
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
Iterador em árvore binária
I Operação: percorrer todos os nós da árvore, por ordem escolhida
I
I
I
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
I Visita da árvore implementada por uma aplicação
I
I
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
I Visita da árvore encapsulada na classe de um iterador
I
I
contexto tem de ser mantido pelo iterador
iterador gere uma pilha para manter registo do estado da visita
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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);
}
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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;
}
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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);
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
Iterador em in-ordem
public class InOrder
extends PostOrder{
public InOrder(
BinarySearchTree theTree){
super(theTree);
}
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;
}
public void advance()
throws ItemNotFound{
if(s.isEmpty()){
if(current == null)
throw new ItemNotFound(
” InOrder Advance”);
current = null;
return;
}
StNode cnode;
...
// First time through
s.push(cnode);
if(cnode.node.left != null)
s.push(new StNode(cnode.node.left));
}
}
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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));
}
}
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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);
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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));
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Revisões – Java
Revisões – Complexidade
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)”);
}
}
Rui Camacho
Algoritmos e Estruturas de Dados II – LEIC
Download