Árvores Balanceadas André Lopes Pereira Luiz Carlos Barboza Júnior
Árvores Balanceadas
André Lopes Pereira
Luiz Carlos Barboza Júnior
Roteiro
Árvores de busca binárias: Organização; Algoritmos de busca, inserção e remoção
em árvores de busca (custos envolvidos); Desvantagens de uma árvore
desbalanceada: Aplicação de AVL; Aplicação de nó crítico e fator de equilíbrio; Rotações simples de dupla; AVL implementada em C.
Árvores de busca binária
Busca
Inserir
Deletar
Todas as chaves da sub-árvore à esquerda são menores do que a chave da raiz, e as chaves da sub-árvore à direita são maiores. Essa regra define árvore de busca binária.
Definição:
Operações:
BuscaBusca (root, x)
Entrada: root (ponteiro pra raiz da árvore) e x número a ser procurado
Saída: node (ponteiro que aponta para o nó contendo x ou nil se o nó não existir)
início
se root = nil ou root^.key então node := root
// root^ e´o conteudo do endereco de root
senao
se x < root^.key então Busca (root^.left,x)
senão Busca (root^.right,x)
fim.
InserirInserir (root,x)
Entrada: root (ponteiro pra raiz da árvore) e x número a ser inserido
Saída: árvore modificada
início
se root = nil então
crie um novo nó apontado por child;
root := child;
root^.key := x;
senao
node := root;
child := root; //para inicializar e ele nao seja null
enquanto node != nil e child != nil faça
se node^.key = x então child := nil
senão
parent := node;
se x < node^.key então node := node^.left
senão node := node^.right
se child != nil então
crie um novo nó apontado por child;
child^.key := x;
child^.left := nil; child^.right := nil;
se x < parent^.key então parent^.left := child
senão parent^.right := child
fim
DeletarDeletar (root,x)
Entrada: root (ponteiro pra raiz ) e x número a ser deletado
Saída: árvore modificada
início
node := root;
enquanto node != nil e node^.key != x faça
parent := node;
se x < node^.key então node := node^.left;
senão node := node^.right;
se node = nil então imprima ("x não está na árvore"); sair
se node != root então
se node^.left = nil então
se x <= parent^.key então parent^.letf := node^.right
senão parent^.right := node^.right
senão se node^.right = nil então
se x <= parent^.key então parent^.left := node^.left
senão parent^.right := node^.left
senão // o caso de 2 filhos
node1 := node^.left
parent1 := node
enquanto node^.right != nil do
parent1:= node1;
node1:= node1^.right;
parent1^.right := node1^.left
node^.key := node1^.key
fim
Deletar: folhas
(...)
se node^.left = nil então
se x <= parent^.key
então
parent^.letf := node^.right
senão
parent^.right := node^.right
senão se node^.right = nil então
se x <= parent^.key
então
parent^.left := node^.left
senão
parent^.right := node^.left
(...)
Deletar: nó com único filho
(...)
se node^.left = nil então
se x <= parent^.key
então
parent^.letf := node^.right
senão
parent^.right := node^.right
senão se node^.right = nil então
se x <= parent^.key
então
parent^.left := node^.left
senão
parent^.right := node^.left
(...)
Deletar: nó com dois filhos
(...)
senão // o caso de 2 filhos
node1 := node^.left
parent1 := node
enquanto node^.right != nil do
parent1:= node1;
node1:= node1^.right;
parent1^.right := node1^.left
node^.key := node1^.key
fim
Custos envolvidos
Pior caso: Percorrer a árvore da raiz até a folha mais distante
para localizar o nó desejado
Tempo de execução dos outros passos é constante
Custo
O (log n)Árvore balanceada
O (n)Lista encadeada
AVL
AVL (Adel’son-Vel’skii e Landis)
Árvore de busca binária que, para cada nó, a diferença entre as alturas de suas sub-árvores é no máximo 1
Definição:
Balance
Fator que indica a diferença entre a altura das sub-árvores da esquerda e da direita, precedido do sinal + (caso a da direita seja maior) ou - (caso a maior seja a da esquerda).
Definição:
Balanceatual
InserçãoEsq ou Dir
Novobalance
0 Esq. | Dir. -1/0 | +1/0
-1 Dir. -1/0
+1 Esq. +1/0
-1 Esq. -1/Deseq.
+1 Dir. +1/Deseq.
BalanceBalance (root)
Entrada: root (ponteiro pra raiz da arvore)
Saída: todos os nós da árvore com o valor de balance
início
se root = nil
altura := -1
senão root^.left = nil e root^.right = nil então
altura := 0;
root^.balance := 0;
// se o no for um folha seu balance e´ 0 (zero)
senão
Esq := Balance (root^.left);
Dir := Balance (root^.right);
root^.balance := Dir - Esq;
altura := Max (Esq, Dir);
retorna (altura + 1)
fim
Nó crítico
(...)
se balance mudou de 0 para +1 ou -1 então retorne sim
se balance mudou de +1 ou -1 para 0 então retorne não
se a resposta for sim então
se o sim for pela direita então balance := balance + 1
se o sim for pela esquerda então balance := balance - 1
se balance => 2 ou balance <= -2 então
esse é o nó crítico. Aplique a rotação de acordo com a tabela:
Balance
Inserirà
Na sub-árvore da
Rotação
-1 Esq. Left Simples(horário)
-1 Esq. Right Dupla(horário)
+1 Dir. Left Dupla(anti-horário)
+1 Dir. Right Simples(anti-horário)
+ 1
Rotação simples
Temp := B^.dir;
B^.dir := A;
A^.esq := temp;
Rotação dupla
Temp := B^.dir;
B^.dir := B^.dir^.esq;
A^.esq := B^.dir^.dir;
Temp^.esq := B;
Temp^.dir := A;
Conclusão
Tipos de dados abstratos que manipulam estas três operações são chamados de dicionários (ordem lexicográfica);
A eficiência da árvore de busca é diretamente relacionada à sua altura. A estratégia é manter a árvore com a altura mínima possível utilizando as regras de AVL;