Árvores balanceadas
O que significa uma árvore estar balanceada, o fator de balanceamento e as rotações, a ferramenta comum das árvores AVL e rubro-negras.
Na árvore binária de busca, buscar, inserir e
remover custam
As árvores balanceadas resolvem esse problema: são árvores de busca que
modificam a inserção e a remoção para que a altura fique sempre
O que é estar balanceada
Uma família de árvores binárias de busca é balanceada se existe uma
constante
Repare que a definição fala de uma família de árvores, definida por alguma regra, e da garantia que a regra dá. Diferentes regras levam a diferentes famílias:
- balanceamento por altura: em todo nó, as alturas da SAE e da SAD diferem de no máximo 1. É o critério das árvores AVL;
- balanceamento por peso: em todo nó, o número de nós da SAE e o da SAD são iguais ou próximos;
- critérios mais relaxados, como o das árvores rubro-negras: nenhum
caminho da raiz até um
NULLtem mais que o dobro do comprimento de outro.
Na página de árvores binárias,
chamamos de balanceada a árvore em que as alturas das subárvores de cada nó
diferem de no máximo 1. Esse é o critério da AVL, e é o significado mais
comum de "balanceada". Mas uma árvore rubro-negra pode ter nós com
subárvores de alturas bem diferentes e, mesmo assim, ter altura
Fator de balanceamento
Para medir o quanto um nó está "torto", comparamos as alturas das suas subárvores.
O fator de balanceamento de um nó
com a convenção de que a árvore vazia tem altura
Alguns livros usam a diferença ao contrário (SAD menos SAE), o que só troca os sinais. E a convenção de altura (folha com altura 0 ou 1) não muda nada: o fator é uma diferença de alturas.
Dois detalhes da figura. Em (a), a árvore não é cheia (40 e 70 têm um filho
só), e mesmo assim todos os nós têm
Na árvore (b), reorganize apenas a subárvore com raiz 30, colocando 20 como raiz dela, com 10 à esquerda e 30 à direita. A árvore continua sendo de busca? Recalcule os fatores: o nó 50 continua desequilibrado?
Ver respostaEsconder resposta
Continua sendo de busca: em ordem, as chaves seguem 10, 20, 30, 50, 70.
A nova subárvore com raiz 20 tem altura 1 e fatores 0 em todos os seus
nós. O 50 passa a ter
O programa abaixo insere as chaves da entrada em uma ABB comum e imprime, em
ordem, a altura e o fator de cada nó. A entrada é a da árvore (b); troque
por 7 e 50 30 70 20 40 80 35 para a árvore (a), ou por 7 e
1 2 3 4 5 6 7 para ver uma árvore degenerada.
Esse programa calcula as alturas chamando altura em cada nó, e altura
percorre a subárvore inteira. Quanto custa imprimeFatores em uma árvore
degenerada com
Ver respostaEsconder resposta
O nó de profundidade fatorBalanceamento e por altura).
O total é proporcional a
Rebalancear, mas localmente
A inserção e a remoção da ABB não olham para a forma da árvore. Basta inserir
10, 20 e 30, nessa ordem, para a raiz ficar com
Uma ideia ingênua: depois de cada inserção, copiar as chaves (em ordem simétrica) para um vetor ordenado e reconstruir a árvore inteira, sempre com o elemento do meio como raiz. Isso funciona? Quanto custa?
Ver respostaEsconder resposta
Funciona: a árvore reconstruída tem a menor altura possível. Mas cada
reconstrução percorre e recria os
O desafio que a AVL e a rubro-negra resolvem é rebalancear com mudanças
locais: apenas nos nós do caminho entre a raiz e o ponto da inserção ou da
remoção. Como esse caminho tem
Rotações
Uma rotação reorganiza um nó e um dos seus filhos, trocando quem é pai de quem, sem mudar a ordem das chaves.
Na rotação à direita em
/* Rotação à direita em y: o filho esquerdo x sobe e y vira filho direito
de x. Devolve a nova raiz da subárvore (x). */
No *rotacaoDireita(No *y) {
No *x = y->esq;
y->esq = x->dir; /* a subárvore do meio (B) muda de pai */
x->dir = y;
return x;
}
/* Rotação à esquerda em x: o simétrico da anterior */
No *rotacaoEsquerda(No *x) {
No *y = x->dir;
x->dir = y->esq; /* a subárvore do meio (B) muda de pai */
y->esq = x;
return y;
}São só três atribuições de ponteiros, e nenhuma delas toca nas chaves nem nos valores: os nós mudam de lugar levando o seu par chave-valor junto.
Uma rotação aplicada a uma ABB produz uma ABB com as mesmas chaves e custa
Demonstraçãotente antes de abrir
Pelo teorema da ordem simétrica, basta
mostrar que a em-ordem não muda. Antes da rotação à direita, a em-ordem da
subárvore é a de
O que a rotação muda são as profundidades:
Na rotação à direita em
Demonstraçãotente antes de abrir
Seja
É por isso que a rotação conserta um nó com a SAE alta demais: a parte mais
funda, em
O programa abaixo monta uma árvore com a SAE mais alta, aplica uma rotação à direita na raiz (a altura cai de 3 para 2) e depois a desfaz com uma rotação à esquerda. A em-ordem é a mesma nos dois momentos.
A rotação muda a raiz da subárvore, e quem chama precisa atualizar o
ponteiro que apontava para ela: raiz = rotacaoDireita(raiz); ou
r->esq = rotacaoDireita(r->esq);. É o mesmo cuidado da inserção recursiva
na ABB, e esquecê-lo é o erro do Programa 2.
Panorama das árvores balanceadas
| Árvore | Como mantém o balanceamento | Altura no pior caso | Onde aparece |
|---|---|---|---|
| AVL | cerca de | aplicações com muito mais buscas que alterações | |
| Rubro-negra | cores nos nós e regras sobre elas; rotações e recolorações | std::map do C++, TreeMap do Java, núcleo do Linux | |
| 2-3 e 2-3-4 | nós com 2, 3 (ou 4) filhos; todas as folhas no mesmo nível | base conceitual das rubro-negras | |
| B, B+ | nós com muitas chaves e muitos filhos | muito pequena | bancos de dados e sistemas de arquivos |
A AVL e a rubro-negra resolvem o mesmo problema com trocas diferentes: a AVL é balanceada com mais rigor e, por isso, um pouco mais baixa, o que favorece as buscas; a rubro-negra tolera mais desequilíbrio e, em troca, costuma reorganizar menos nas inserções e remoções. Nesta disciplina, estudaremos a AVL e a LLRB (left-leaning red-black tree), uma variante da rubro-negra proposta por Sedgewick em 2008, com código bem mais curto, que corresponde diretamente às árvores 2-3. As árvores B ficam para Estrutura de Dados II.
Exercícios
Encontre e corrija o erro
Programa 1
Resposta
A rotação faz y->esq = NULL em vez de y->esq = x->dir: a subárvore do meio
(x->dir ser sobrescrito:
No *x = y->esq;
y->esq = x->dir;
x->dir = y;
return x;Programa 2
Resposta
A rotação em 30 é feita corretamente, mas o retorno é descartado: o 60 continua apontando para o 30, que agora é filho direito do 20 e ficou sem filhos. O 20 e o 10 desaparecem da árvore (e vazam). O ponteiro que apontava para a subárvore precisa receber a nova raiz:
raiz->esq = rotacaoDireita(raiz->esq);Programa 3
Resposta
A função só verifica o fator da raiz, que é 0 (as duas subárvores têm
altura 3), e responde "sim". Mas o critério vale para todo nó: o 30 tem
if (fb < -1 || fb > 1)
return false;
return ehBalanceada(r->esq) && ehBalanceada(r->dir);Implemente
Fatores de balanceamento em O(n). Grave o fator de balanceamento de todos
os nós de uma árvore, na ordem simétrica, em altura em cada nó
não termina a tempo.
A altura de um nó depende das alturas dos filhos. Em que ordem os nós precisam ser processados para que as alturas dos filhos já estejam prontas?
Ver dica 1Esconder dica 1
De baixo para cima: uma função recursiva que devolve a altura da subárvore pode calcular o fator do nó com os dois valores que recebeu das chamadas nos filhos.
Ver dica 2Esconder dica 2
O fator de cada nó vai para a posição dele na ordem simétrica. Reserve essa posição (com um contador passado por ponteiro) entre as chamadas para a SAE e para a SAD, e grave o fator depois da segunda chamada.
Rotações. Implemente rotacaoDireita e rotacaoEsquerda. Os testes aplicam
sequências de rotações em vários pontos de uma ABB (incluindo rotações sem
subárvore do meio) e conferem a forma da árvore, a ordem das chaves e os
valores. A última bateria faz 300 mil rotações aleatórias em uma árvore com 100
mil nós.
Referências
- W. Celes, R. Cerqueira e J. L. Rangel. Introdução a Estruturas de Dados: com técnicas de programação em C. 2ª ed. Grupo GEN, 2016.
- A. Backes. Estrutura de Dados Descomplicada em Linguagem C. Elsevier, 2016.
- R. Sedgewick e K. Wayne. Algorithms. 4ª ed. Addison-Wesley, 2011. Seção 3.3.
- R. Sedgewick. Left-leaning Red-Black Trees. 2008.
- D. Galles. Visualizações interativas: ABB, AVL e rubro-negra. University of San Francisco.
Árvores binárias de busca
A árvore binária em que a posição de cada chave é dada pela ordem. Busca, inserção e remoção em tempo proporcional à altura, com o TAD Arvore guardando pares chave-valor.
Árvores AVL
A árvore AVL, uma árvore de busca que guarda a altura em cada nó e usa rotações para manter |fb| ≤ 1 em todos os nós, com altura sempre O(log n).