You are on page 1of 11

Estruturas de Dados

Árvores – Parte II:


EDs & Algoritmos
Prof. Ricardo J. G. B. Campello
Parte deste material é baseado em adaptações e extensões de slides
disponíveis em http://ww3.datastructures.net (Goodrich & Tamassia).

O TAD Árvore
Operações Genéricas: Operações de Consulta:
 size(T): no. de nós da árvore.  isInternal(T, p): Nó p é interno ?
 isEmpty(T): árvore T vazia ?  isExternal(T, p): Nó p é externo ?

Operações de Acesso:  isRoot(T, p): Nó p é raiz de T ?

 root(T): retorna referência Operações de Atualização:


para o nó raiz ou para nulo  swap(T, p, q): Troca elementos
se árvore T for vazia. da árvore T armazenados nos
 parent(T, p): retorna ref. p/ o nós referenciados por p e q.
nó pai do nó referenciado por  replace(T, p, e): Substitui por “e”
p ou para nulo se p é raiz. o elemento armazenado no nó
 children(T, p): retorna lista referenciado por p.
de referências para os filhos  ...
do nó referenciado por p.
 Lista vazia se p for folha.
2

1
TAD Árvore Binária
O TAD Árvore Binária estende o TAD árvore, ou seja, herda
todas as suas operações.

Operações Adicionais:
 leftChild(T, p): retorna referência para o nó filho esquerdo do nó
referenciado por p ou para nulo (p. ex. se p é externo).

 rightChild(T, p): retorna referência para o nó filho direito do nó


referenciado por p ou para nulo (p. ex. se p é externo).

 sibling(T, p): retorna referência para o nó irmão do nó referenciado


por p ou para nulo se p é filho único (árvore T imprópria).

O TAD Árvore Binária


Árvores são estruturas muito flexíveis, dando margem à diversos
tipos de operações possíveis para um TAD.

Por esta razão, TADs Árvore podem diferir bastante de


implementação para implementação, especialmente no que diz
respeito aos métodos de modificação. Exemplo:
 Dois possíveis métodos que permitem modificar a estrutura:

expandExternal(T, v) removeAboveExternal(T, w)
v v
A A A B

∅ ∅ B C w
 Permitem construir ou destruir completamente qualquer árvore binária!
4

2
Estrutura em Arranjo para Árvores Binárias
Utiliza o conceito de função
numeradora por nível: 1

 f(v) = 1 se v é a raiz da árvore T. 2 3


 f(v) = 2f(u) se v é filho esq. de u.
4 5 6 7
 f(v) = 2f(u)+1 se v é filho dir. de u.

Cada nó da árvore é armazenado 10 11


na célula de um arranjo
 O índice é dado pela função
numeradora.
 O valor da função numeradora
fornece imediatamente a
localização dos filhos e do pai.

Estrutura em Arranjo para Árvores Binárias


Tamanho do arranjo é N = pM+1, 1
onde pM é o valor máximo de f(v). n=7
2 3 N = 16
 Para índice inicial do arranjo = 0
7
Problema:
6 15
 Se a árvore não for completa,
células do arranjo serão alocadas 14
desnecessariamente.
 Espaço é O(N) independente do 1 n=4
número n de nós da árvore.
3 N = 16
 No pior caso, a demanda de
memória é Exponencial! 7
 N = 2(n+1)/2 para ABs próprias 15
 N= 2n para ABs impróprias

3
Estrutura em Arranjo para ABs
 Resumo:
a
1 2 3 4 5 6 7 ...
b c
a b c d e f g ...
d e f g

 Vantagens:
 Simplicidade
 Espaço apenas para armazenar conteúdo (elementos)
 ligações estão implícitas nos valores dos índices
 Desvantagens:
 Espaços vagos se árvore não é completa
 Inadequada para árvores com tamanho variável

Estrutura Encadeada para Árvores Binárias


Um nó é representado por ∅
um nodo, que armazena:
 Elemento.
 Ponteiro para pai. B
 Ponteiro para filho esquerdo.
 Ponteiro para filho direito. ∅ ∅
Espaço O(n)!
A D
B
∅ ∅ ∅ ∅
A D
C E
C E
8

4
Tempos de Execução nas Duas Implementações

Operação Arranjo / Encadeada


swap, replace O(1)
root, parent, children O(1)
leftChild, rightChild, sibling O(1)
isInternal, isExternal , isRoot O(1)
expandExternal, O(1)
removeAboveExternal (encadeada)

Estrutura Encadeada para Árvores


Um nó é representado ∅
por um nodo, que
armazena: B
 Elemento
 Ponteiro para nó pai. ∅ ∅
 Ponteiro para lista de
ponteiros para nós A D F
filhos.

A D F
∅ ∅
C E
C E
10

5
O(n), onde
n é o no.
Percurso Pré-Fixado de nodos
Um “percurso” visita os nodos de Algoritmo PreOrder(T, v)
uma árvore de forma sistemática. visite(T, v)
 travessia ou caminhamento se isInternal(T, v) então
Em um percurso pré-fixado, um para w ∈ children(T, v) faça
nodo é visitado antes dos seus PreOrder(T, w)
descendentes. * Acesso seqüencial à lista children a
partir do primeiro filho.
Exemplo de Aplicação:
 imprimir doc. estruturado 1
Documento

2 5 9
Capítulo 1 Capítulo 2 Referências

3 4 6 7 8
Seção 1.1 Seção 1.2 Seção 2.1 Seção 2.2 Seção 2.3

Percurso Pré-Fixado
Caso Particular
 Árvores Binárias
Algoritmo PreOrder(T, v)
visite(T, v)
se isInternal(T, v) então
PreOrder(T, leftChild(T, v))
PreOrder(T, rightChild(T, v))
* Chamada: PreOrder(T, root(T))

6
O(n), onde
n é o no.
Percurso Pós-Fixado de nodos
Em um percurso pós-fixado, um Algoritmo PosOrder(T, v)
nodo é visitado após seus
se isInternal(T, v) então
descendentes.
para w ∈ children(T, v) faça
Útil quando alguma propriedade de
um nodo depende da propriedade PosOrder(T, w)
dos seus descendentes. visite(T, v)
* Acesso seqüencial à lista
Exemplo de Aplicação: children a partir do primeiro filho.
 calcular o espaço utilizado em 9
árvores de arqs e diretórios.
cs16/
8
3 7
todo.txt
homeworks/ programs/
1K

1 2 4 5 6
h1c.doc h1nc.doc DDR.java Stocks.java Robot.java
3K 2K 10K 25K 20K 13

Percurso Pós-Fixado
Caso Particular
 Árvores Binárias
Algoritmo PosOrder(T, v)
se isInternal(T, v) então
PosOrder(T, leftChild(T, v))
PosOrder(T, rightChild(T, v))
visite(T, v)
* Chamada: PosOrder(T, root(T))

7
Avaliação de Expressões Aritméticas
Especialização de um Algoritmo EvalExpr(T, v)
percurso pós-fixado: se isInternal(T, v) então
x ← EvalExpr(T, leftChild(T, v))
visite(T, v) calcula e
y ← EvalExpr(T, rightChild(T, v))


retorna a op. x ◊ y se v
◊ ← elem(T, v)
for interno, c.c. retorna o
valor armazenado em v. retorne x ◊ y
senão retorne elem(T, v)
+ * Chamada: EvalExpr(T, root(T))

× ×

2 − 3 2 Árvores
Binárias
5 1
PS. Assume disponível no TAD AB operação elem(T, v), que retorna info. do nó referenciado por v.

Percurso Inter-Fixado
Em um percurso inter- Algoritmo InOrder(T, v)
fixado um nodo é visitado se isInternal(T, v) então
após sua sub-árvore InOrder(T, leftChild(T, v))
esquerda e antes da sua
sub-árvore direita. visite(T, v)
se isInternal(T, v) então
Exemplo de Aplicação:
InOrder(T, rightChild(T, v) )
 Percurso não decrescente * Chamada: InOrder(T, root(T))
em uma árvore binária de
busca onde cada nodo 6
interno armazena um
elemento maior (menor) ou 2 8
igual aos elementos
armazenados na sua sub- 1 4 7 9
árvore esquerda (direita).
3 5
16

8
Exercícios
 Escreva um algoritmo em pseudo-código que receba
uma árvore T e uma referência para um nó da árvore,
retornando a profundidade daquele nó na árvore.

 O algoritmo deve ser iterativo (não-recursivo).

 O algoritmo deve usar apenas as operações do TAD


Árvore (slide 3), independente da ED utilizada para
implementá-lo.

17

Exercícios
 Faça um algoritmo em pseudo-código para cálculo da altura de
uma árvore binária própria T recebida como parâmetro:

 O algoritmo deve ser recursivo.

 Para tanto, a árvore não deve ser o seu único parâmetro.

 O algoritmo deve usar apenas as operações do TAD Árvore


Binária (slides 3 e 5), independente da ED utilizada para
implementá-lo.

 Você deve mostrar que o tempo de execução de pior caso do


algoritmo é linear em termos do número de nós da árvore.

18

9
Exercícios
 Seja a seguinte expressão aritmética:
 ( −27 / ( ( 2 × (a + 8) ) − ( (3 × b) + 18 ) ) ) / ( c − 10 )
Represente essa expressão em uma árvore estritamente binária
de expressão aritmética.

 Mostre em detalhes como essa árvore ficaria armazenada em


um arranjo segundo a estratégia de implementação baseada em
função numeradora por nível.

 Mostre graficamente e em detalhes como essa árvore ficaria


armazenada em uma estrutura dinâmica.

 Mostre o conteúdo de cada nó da árvore segundo a ordem de


visitas aos nós, nos seguintes percursos:
 pré-fixado, pós-fixado e inter-fixado.
19

Exercícios
 Implemente o TAD Árvore Binária em Linguagem C:
 Via ED estática (arranjo).
 Via ED dinâmica.
 Faça a implementação de um dos TADs acima de modo a
armazenar números inteiros nos nodos da árvore. Então
implemente operações para imprimir todos esses números via:
 Percurso pré-fixado.
 Percurso pós-fixado.
 Percurso inter-fixado.
 Nota: Cada visita deve imprimir o valor do nó correspondente.

20

10
Bibliografia
M. T. Goodrich & R. Tamassia, Estruturas de Dados e
Algoritmos em Java, Bookman, 2002

M. T. Goodrich & R. Tamassia, Data Structures and


Algorithms in C++/Java, John Wiley & Sons, 2002/2005

J. L. Szwarcfiter & L. Markenzon, Estruturas de Dados e seus


Algoritmos, LTC, 1994
A. V. Aho, J. E. Hopcroft & J. Ullman, Data Structures and
Algorithms Addison Wesley, 1983
A. M. Tenembaum et al., Data Structures Using C, Prentice-
Hall, 1990

11