O documento discute a implementação de árvores binárias em Java. Resume que árvores binárias são estruturas de dados hierárquicas onde cada nó tem no máximo dois filhos, e discute métodos como inserção, busca, remoção e sucessor de nós na árvore.
2
É uma estruturade dados caracterizada por:
Ou não tem elemento algum (árvore vazia).
Ou tem um elemento distinto, denominado raiz, com dois
apontamentos para dois elos diferentes, denominadas sub-
árvore esquerda e sub-árvore direita.
Arvore Binária
Exemplos:
a) b)
4
Arvores Balanceadas
Umaarvore é considerada balanceada quando suas sub-
arvores a esquerda e a direita possuem a mesma altura.
A arvore não balanceada é definida como degenerada.
Exemplos:
arvore binária
balanceada
arvore binária
degenerada
a) b)
5.
5
Classe No
Uma arvorebinária precisa de uma classe de
objetos Nós, assim como vimos na lista
duplamente encadeada:
class No {
public long item;
public No esq;
public No dir;
}
espaço para armazenamento da
informação (chave)
Um espaço para armazenar uma
referência da localização na
memória onde o Nó a esquerda
se encontra.
Um espaço para armazenar a
referência do Nó a direita.
6.
6
Nó
esq =
dir =
item= 14
Nó
esq =
dir =
item = 4
Nó
esq =
dir =
item = 16
Nó
esq = NULL
dir = NULL
item = 3
Nó
esq = NULL
dir = NULL
item = 9
Nó
esq = NULL
dir = NULL
item = 15
Nó
esq = NULL
dir = NULL
item = 18
As referencias
são para outras
sub-arvores
root
Elos de uma arvore binária
7.
7
Nó
esq =
dir =
item= 14
Nó
esq =
dir =
item = 4
Nó
esq =
dir =
item = 16
Nó
esq = NULL
dir = NULL
item = 3
Nó
esq = NULL
dir = NULL
item = 9
Nó
esq = NULL
dir = NULL
item = 15
Nó
esq = NULL
dir = NULL
item = 18
root = null
A árvore pode não ter nenhum elemento (árvore vazia)
Elos de uma arvore binária
8.
8
Implementação
private No root;
ClasseTree:
Campo Construtor
public Tree() { root=null; }
Métodos
inserir: Insere itens na arvore
buscar: Retorna Nó procurado ou null
remover: Retorna verdadeiro se removeu item
no_sucessor: Retorna o Nó sucessor ao passado no
parâmetro
caminhar: (inOrder, preOrder, posOrder, altura,
folhas, min, max, contarNos)
9.
Método: inserir
A inserçãocomeça com a chave sendo atribuida a raiz,
logo após a função começa com uma busca, a-partir da
raiz, comparando a chave com o valor da raiz. Se a
chave é menor ou igual do que a raiz, ela é
introduzida num novo nó a esquerda da raiz, ou na
direita caso a chave seja maior que a raiz, e assim
sucessivamente, item a item, os nós são criados.
Exemplo:
Itens a serem adicionados:
25, 11, 42, 6, 19, 37 e 14
10.
Método: inserir
public voidinserir(long v) {
No novo = new No();
novo.item = v;
novo.dir = null;
novo.esq = null;
if (root == null)
root = novo;
else {
// inserir aqui
// trecho de código
// para tratamento
// caso árvore não vazia
}
}
Entrada: item que deseja inserir Saída: não há
Criando objeto Nó e
armazenando na referencia
novo
se arvore vazia
11.
No atual =root;
No anterior;
while (true) {
anterior = atual;
if (v <= atual.item) {
atual = atual.esq;
if (atual == null) {
anterior.esq = novo;
return; }
}
else {
atual = atual.dir;
if (atual == null) {
anterior.dir = novo;
return; }
}
} // fim do laço while
trecho de código para tratamento caso não raiz (arvore não vazia)
começa a procurar desde raiz
Adiciona a esquerda
e sai
Adiciona a direita
e sai
Caminha para esquerda
Caminha para direita
Guarda o Nó anterior
12.
12
Método: buscar
public Nobuscar(long chave) {
if (root == null) return null;
No atual = root;
while (atual.item != chave) {
if (chave < atual.item )
atual = atual.esq;
else
atual = atual.dir;
if (atual == null)
return null;
}
return atual;
}
Entrada: chave
Saída: Nó que procura ou null caso não encontre a chave
começa a procurar desde raiz
se arvore vazia
enquanto nao encontrou
caminha para esquerda
caminha para direita
encontrou uma folha -> sai
Saiu do laço while e chegou
aqui é porque encontrou item
13.
Método: remover
O processode exclusão de um nó é o mais complexo.
Para excluir um nó de uma árvore binária, deve-se
considerar três casos distintos:
Remoção da folha
A exclusão de um nó que se encontra no fim da árvore, isto é, na
folha, é o caso mais simples de exclusão. Basta remover o nó da
árvore
14.
14
Remoção de umnó com “filho”
Caso o nó que será excluído tenha um único "filho", o "avô"
herda o "filho".
15.
15
Remoção de umnó com dois “filhos”
Se o nó a ser excluído tiver dois "filhos", o processo de
exclusão poderá operar de duas maneiras diferentes:
Substituir o valor do nó a ser retirado pelo valor sucessor (o
nó mais à esquerda da sub-árvore direita).
16.
Método: remover
public booleanremover(long v) {
if (root == null) return false;
No atual = root;
No pai = root;
boolean filho_esq = true;
while ( atual.item != v) {
pai = atual;
if ( v < atual.item ) {
atual = atual.esq;
filho_esq = true;
} else {
atual = atual.dir;
filho_esq = false;
}
if (atual == null) return false;
} // fim laço while busca
Entrada: item que deseja remover
Saída: verdadeiro ou falso
Enquanto não encontrou
Caminha a esquerda
Caminha a direita
Chegou em uma folha
17.
public boolean remover(longv) {
if (root == null) return false;
No atual = root;
No pai = root;
boolean filho_esq = true;
while ( atual.item != v) {
pai = atual;
if ( v < atual.item ) {
atual = atual.esq;
filho_esq = true;
} else {
atual = atual.dir;
filho_esq = false;
}
if (atual == null) return false;
} // fim laço while busca
Método: remover
Entrada: item que deseja remover
Saída: verdadeiro ou falso
Se terminou o laço de busca
sem sair do método remover
quer dizer que:
Encontrou o valor (v)
"atual": contem a
referencia ao No a ser
eliminado
"pai": contem a
referencia para o pai do
No a ser eliminado
"filho_esq": é
verdadeiro se atual é filho
a esquerda do pai
18.
Método: remover
Entrada: itemque deseja remover
Saída: verdadeiro ou falso
atual.item =
pai.item =
filho_esq =
atual.item = 11
pai.item = 25
filho_esq = true
public boolean remover(long v) {
if (root == null) return false;
No atual = root;
No pai = root;
boolean filho_esq = true;
while ( atual.item != v) {
pai = atual;
if ( v < atual.item ) {
atual = atual.esq;
filho_esq = true;
} else {
atual = atual.dir;
filho_esq = false;
}
if (atual == null) return false;
} // fim laço while busca
19.
if (atual.esq ==null && atual.dir == null)
{
if (atual == root ) root = null;
else if (filho_esq) pai.esq = null;
else pai.dir = null;
}
Eliminando uma folha
atual.item = 6
pai.item = 11
filho_esq = true
Se não possui nenhum filho (é uma folha), elimine-o
20.
Se é paie não possui filho a direita
atual.item = 19
pai.item = 11
filho_esq = false
Substitui pela sub-árvore a direita
else if (atual.dir == null) {
if (atual == root) root = atual.esq;
else if (filho_esq) pai.esq = atual.esq;
else pai.dir = atual.esq;
}
pai.dir
atual.esq
21.
Se é paie não possui filho a esquerda
atual.item = 6
pai.item = 11
filho_esq = true
Substitui pela sub-árvore a esquerda
else if (atual.esq == null) {
if (atual == root) root = atual.dir;
else if (filho_esq) pai.esq = atual.dir;
else pai.dir = atual.dir;
}
pai.esq
atual.dir
22.
Se possui maisde um filho
Se for um avô ou outro grau maior de parentesco
else {
No sucessor = no_sucessor(atual);
if (atual == root) root = sucessor;
else if (filho_esq) pai.esq = sucessor;
else pai.dir = sucessor;
sucessor.esq = atual.esq;
}
return true; // removeu item retorna true
} // fim método remover
Usando sucessor que seria a referencia ao Nó mais a esquerda da sub-
árvore a direita do Nó que deseja-se remover
23.
No sucessor =no_sucessor(atual);
if (atual == root) root = sucessor;
else if (filho_esq) pai.esq = sucessor;
else pai.dir = sucessor;
sucessor.esq = atual.esq;
Trecho de código
atual.item = 11
pai.item = 25
filho_esq = true
1
2
3
4
5
24.
public No no_sucessor(Noapaga) {
No paidosucessor = apaga;
No sucessor = apaga;
No atual = apaga.dir;
while (atual != null) {
paidosucessor = sucessor;
sucessor = atual;
atual = atual.esq;
}
if (sucessor != apaga.dir) {
paidosucessor.esq = sucessor.dir;
sucessor.dir = apaga.dir;
}
return sucessor;
}
Método: no_sucessor
Retorno:
apaga
paisucessor
sucessor
atual
Entrada:
25.
public No no_sucessor(Noapaga) {
No paidosucessor = apaga;
No sucessor = apaga;
No atual = apaga.dir;
while (atual != null) {
paidosucessor = sucessor;
sucessor = atual;
atual = atual.esq;
}
if (sucessor != apaga.dir) {
paidosucessor.esq = sucessor.dir;
sucessor.dir = apaga.dir;
}
return sucessor;
}
Método: no_sucessor
Retorno:
apaga
sucessor
atual
paisucessor
sucessor
atual
Entrada:
paisucessor
26.
public No no_sucessor(Noapaga) {
No paidosucessor = apaga;
No sucessor = apaga;
No atual = apaga.dir;
while (atual != null) {
paidosucessor = sucessor;
sucessor = atual;
atual = atual.esq;
}
if (sucessor != apaga.dir) {
paidosucessor.esq = sucessor.dir;
sucessor.dir = apaga.dir;
}
return sucessor;
}
Método: no_sucessor
Retorno:
apaga
sucessor
atual
paisucessor
sucessor
atual
Entrada:
paisucessor
sucessor
atual = null
true
27.
public No no_sucessor(Noapaga) {
No paidosucessor = apaga;
No sucessor = apaga;
No atual = apaga.dir;
while (atual != null) {
paidosucessor = sucessor;
sucessor = atual;
atual = atual.esq;
}
if (sucessor != apaga.dir) {
paidosucessor.esq = sucessor.dir;
sucessor.dir = apaga.dir;
}
return sucessor;
}
Método: no_sucessor
Retorno:
apaga
sucessor
atual
paisucessor
sucessor
atual
sucessor
atual = null
Entrada:
true
paisucessor
sucessor
28.
public No no_sucessor(Noapaga) {
No paidosucessor = apaga;
No sucessor = apaga;
No atual = apaga.dir;
while (atual != null) {
paidosucessor = sucessor;
sucessor = atual;
atual = atual.esq;
}
if (sucessor != apaga.dir) {
paidosucessor.esq = sucessor.dir;
sucessor.dir = apaga.dir;
}
return sucessor;
}
Método: no_sucessor
Retorno:
apaga
sucessor
atual
paisucessor
sucessor
atual = null
Entrada:
true
paisucessor
sucessor
null
29.
public No no_sucessor(Noapaga) {
No paidosucessor = apaga;
No sucessor = apaga;
No atual = apaga.dir;
while (atual != null) {
paidosucessor = sucessor;
sucessor = atual;
atual = atual.esq;
}
if (sucessor != apaga.dir) {
paidosucessor.esq = sucessor.dir;
sucessor.dir = apaga.dir;
}
return sucessor;
}
Método: no_sucessor
sucessor
apaga
paisucessor
sucessor
atual
paisucessor
sucessor
atual = null
Entrada:
true
null
apaga.dir
Retorno:
30.
atual.item = 11
pai.item= 25
filho_esq = true
pai.esq
No sucessor = no_sucessor(atual);
if (atual == root) root = sucessor;
else if (filho_esq) pai.esq = sucessor;
else pai.dir = sucessor;
sucessor.esq = atual.esq;
Trecho de código
1
2
3
4
5
sucessor
pai.esq = sucessor
Linha 3:
atual.esq
31.
atual.item = 11
pai.item= 25
filho_esq = true
pai.esq
atual.esq
Trecho de código
1
2
3
4
5
pai.esq = sucessor
Linha 3:
sucessor
No sucessor = no_sucessor(atual);
if (atual == root) root = sucessor;
else if (filho_esq) pai.esq = sucessor;
else pai.dir = sucessor;
sucessor.esq = atual.esq;
32.
pai.esq
atual.esq
Trecho de código
1
2
3
4
5
pai.esq=sucessor
Linha 3: Linha 5:
sucessor.esq =
atual.esq
sucessor sucessor
No sucessor = no_sucessor(atual);
if (atual == root) root = sucessor;
else if (filho_esq) pai.esq = sucessor;
else pai.dir = sucessor;
sucessor.esq = atual.esq;
33.
public No no_sucessor(Noapaga) {
No paidosucessor = apaga;
No sucessor = apaga;
No atual = apaga.dir;
while (atual != null) {
paidosucessor = sucessor;
sucessor = atual;
atual = atual.esq;
}
if (sucessor != apaga.dir) {
paidosucessor.esq = sucessor.dir;
sucessor.dir = apaga.dir;
}
return sucessor;
}
Método: no_sucessor
Vai para a sub-
arvore a direita
Caminha para o Nó
mais a esquerda
Se sucessor não é
o filho a direita do
Nó que deverá ser
eliminado
Pai herda os filhos
do sucessor que
sempre serão a
direita
Guardando a
referencia a direita
do sucessor para
quando ele
assumir a posição
correta na arvore
34.
34
Método: caminhar
public voidcaminhar() {
System.out.print("n Exibindo em ordem: ");
inOrder(root);
System.out.print("n Exibindo em pos-ordem: ");
posOrder(root);
System.out.print("n Exibindo em pre-ordem: ");
preOrder(root);
System.out.print("n Altura da arvore: " + altura(root));
System.out.print("n Quantidade de folhas: " + folhas(root));
System.out.print("n Quantidade de Nós: " + contarNos(root));
if (root != null ) { // se arvore nao esta vazia
System.out.print("n Valor minimo: " + min().item);
System.out.println("n Valor maximo: " + max().item);
}
}
Chamada a métodos recursivos
Entrada: Não há
Saída: Não tem
35.
35
Método: inOrder
public voidinOrder(No atual) {
if (atual != null) {
inOrder(atual.esq);
System.out.print(atual.item + " ");
inOrder(atual.dir);
}
}
Primeiro visita o Nó a esquerda, depois a raiz (imprime o
item), finalizando com o Nó a direita.
Entrada: O Nó raiz
Saída: Não tem retorno
36.
36
Método: posOrder
public voidposOrder(No atual) {
if (atual != null) {
posOrder(atual.esq);
posOrder(atual.dir);
System.out.print(atual.item + " ");
}
}
Primeiro visita o Nó a esquerda, depois o Nó a direita,
finalizando com a raiz (imprime o item).
Entrada: O Nó raiz
Saída: Não tem retorno
37.
37
Método: preOrder
public voidpreOrder(No atual) {
if (atual != null) {
System.out.print(atual.item + " ");
preOrder(atual.esq);
preOrder(atual.dir);
}
}
Primeiro visita a raiz (imprime o item), depois o Nó a
esquerda, finalizando com o Nó a direita.
Entrada: O Nó raiz
Saída: Não tem retorno
38.
38
Método: folhas
public intfolhas(No atual) {
if (atual == null) return 0;
if (atual.esq == null && atual.dir == null)
return 1;
return folhas(atual.esq) + folhas(atual.dir);
}
Entrada: O Nó raiz
Saída: Numero de folhas da arvore
39.
39
Método: folhas
public intfolhas(No atual) {
if (atual == null) return 0;
if (atual.esq == null && atual.dir == null)
return 1;
return folhas(atual.esq) + folhas(atual.dir);
}
Entrada: O Nó raiz
Saída: Numero de folhas da arvore
A arvore não possui itens ou chegou no final e não encontrou mais nenhum item
retorna zero
Retorne chamada recursiva da função contando a quantidade de folhas a
esquerda mais a direita da arvore
Se encontrou somente um item (raiz) ou chegou em uma folha,
retorna 1
40.
40
Método: contarNos
public intcontarNos(No atual) {
if (atual == null)
return 0;
else
return ( 1 + contarNos(atual.esq) +
contarNos(atual.dir) );
}
Entrada: O Nó raiz
Saída: Numero de Nós
Arvore vazia ou chegou no final e não encontrou mais nenhum item retorna zero
Senão retorne o valor 1 + chamada recursiva da função
contando a quantidade de nós a esquerda mais a direita da
arvore
41.
41
Método: min
public Nomin() {
No atual = root;
No anterior = null;
while (atual != null) {
anterior = atual;
atual = atual.esq;
}
return anterior;
}
Entrada: não há
Saída: No mais a esquerda (Nó mínimo)
42.
42
Método: min
public Nomin() {
No atual = root;
No anterior = null;
while (atual != null) {
anterior = atual;
atual = atual.esq;
}
return anterior;
}
Entrada: não há
Saída: No mais a esquerda (Nó mínimo)
Começa na raiz
Enquanto não encontrar um Nó
igual a null
Guarda o Nó anterior
Caminha para o filho a esquerda
43.
43
Método: max
public Nomax() {
No atual = root;
No anterior = null;
while (atual != null) {
anterior = atual;
atual = atual.dir;
}
return anterior;
}
Entrada: não há
Saída: No mais a direita (Nó máximo)
44.
44
Método: max
public Nomax() {
No atual = root;
No anterior = null;
while (atual != null) {
anterior = atual;
atual = atual.dir;
}
return anterior;
}
Entrada: não há
Saída: No mais a direita (Nó máximo)
Começa na raiz
Enquanto não encontrar um Nó
igual a null
Guarda o Nó anterior
Caminha para o filho a direita
45.
Exemplo de usoda classe Tree:
class TreeBinApp {
public static void main(String[] args) {
Scanner le = new Scanner(System.in);
Tree arv = new Tree();
int opcao;
long x;
System.out.print("n Programa Arvore binaria de long");
do {
System.out.print("n***********************************");
System.out.print("nEntre com a opcao:");
System.out.print("n ----1: Inserir");
System.out.print("n ----2: Excluir");
System.out.print("n ----3: Pesquisar");
System.out.print("n ----4: Exibir");
System.out.print("n ----5: Sair do programa");
System.out.print("n***********************************");
System.out.print("n-> ");
opcao = le.nextInt();
switch(opcao) {
case 1: {
System.out.print("n Informe o valor (long) -> ");
x = le.nextLong();
46.
x = le.nextLong();
arv.inserir(x);
break;
}
case2: {
System.out.print("n Informe o valor (long) -> ");
x = le.nextLong();
if ( !arv.remover(x) )
System.out.print("n Valor nao encontrado!");;
break;
}
case 3: {
System.out.print("n Informe o valor (long) -> ");
x = le.nextLong();
if( arv.buscar(x) != null )
System.out.print("n Valor Encontrado");
else
System.out.print("n Valor nao encontrado!");
break;
}
case 4: {
arv.caminhar();
break;
}
48
Atividades
1. No códigoJava para uma árvore, o ________ e a ________
são geralmente classes separadas.
.2. Uma sub-árvore de uma árvore binária sempre tem
(a) Uma raiz que é um filho da raiz da árvore principal
(b) Uma raiz não conectada a raiz da árvore principal
(c) Menos Nós que a árvore principal
(d) Uma irmã com mesmo número de Nós
3. Verdadeiro ou falso:
(a) Eliminar um Nó com um filho de uma árvore binária de busca envolve
encontrar o sucessor desse Nó.
(b) Nem todas as árvores são binárias.
(c) Uma árvore não balanceada é uma árvore na qual a raiz ou algum
outro Nó tenha muito mais filhos à esquerda do que filhos à direita ou
vice-versa.
49.
49
Atividades
4. Trabalho 2- Exercício 6. Desenhe uma arvore binária
usando a seguinte sequencia de dados de entrada:
(a) 25, 11, 42, 6, 19, 37 e 14
(b) 11, 22, 33, 44, -11, -33 e -22
(c) 14, 4, 15, 3, 9, 13, 18, 7, 11, 16, 20, 5, 17, 4 e 5
Responda: Quantas folhas, nós e qual a altura das arvores (a), (b) e (c).
Escreva a arvore (b) e (c) em pré-ordem e pós-ordem.
Desenhe as arvores (a), (b) e (c) depois da inserção do nó 21 e da
remoção do nó 11 para as arvores (a) e (b) e nó 18 para arvore (c).
5. Desenvolva um programa árvore binária de:
(a) double
(b) caracteres
(c) strings
50.
50
Atividades
6. Desenvolva umprograma árvore binária para um objeto
que represente uma agenda telefônica, use o nome como
campo chave