Árvore AVL

Comece com uma árvore AVL aleatória e insira, busque ou exclua valores passo a passo: veja o fator de balanceamento de cada nó, as rotações LL, RR, LR e RL, sua forma em array e o código C++ destacado.

Tudo é simulado neste navegador; nada é enviado a nenhum servidor.

Sem passos

Sem passos

Árvore AVL

Índice no array · Fator de balanceamento

60[0]+145[1]+185[2]+167[5]018[3]-153[4]028[8]0

Forma em array

Os filhos do índice i estão em 2i+1 e 2i+2.

  • Sem relação
  • Já percorrido
  • Sendo comparado
  • Encontrado
  • Novo
  • A excluir
  • Sucessor
  • Desbalanceado
  • Pivô

Sem passos

Código

#include <iostream>
#include <algorithm>
using namespace std;
class Node { // Um nó guarda seu valor e ponteiros para seus dois filhos
private: // Atributos privados: só os métodos acessam
int value;
Node* left;
Node* right;
public:
Node(int v) : value(v), left(nullptr), right(nullptr) {}
int getValue() const { return value; }
Node* getLeft() const { return left; }
Node* getRight() const { return right; }
void setValue(int v) { value = v; }
void setLeft(Node* n) { left = n; }
void setRight(Node* n) { right = n; }
};
int height(Node* n) { // Altura: uma folha vale 1 e uma posição vazia (nullptr) vale 0
if (n == nullptr) return 0;
return 1 + max(height(n->getLeft()), height(n->getRight()));
}
int balanceFactor(Node* n) { // Fator de balanceamento: altura esquerda menos altura direita
return height(n->getLeft()) - height(n->getRight());
}
Node* rotateRight(Node* y) { // Rotação simples à direita: o filho esquerdo x sobe e y desce
Node* x = y->getLeft();
y->setLeft(x->getRight());
x->setRight(y);
return x;
}
Node* rotateLeft(Node* x) { // Rotação simples à esquerda: o filho direito y sobe e x desce
Node* y = x->getRight();
x->setRight(y->getLeft());
y->setLeft(x);
return y;
}
Node* rebalance(Node* n) { // Devolve a raiz da subárvore, balanceada
int bf = balanceFactor(n); // Calcula-se o fator de balanceamento do nó
if (bf > 1) { // Pesada à esquerda. Se o filho esquerdo não é pesado à direita, é o caso LL
if (balanceFactor(n->getLeft()) < 0) // O filho esquerdo é pesado à direita: caso LR, girar à esquerda primeiro
n->setLeft(rotateLeft(n->getLeft())); // Primeira rotação do caso LR
return rotateRight(n); // Rotação à direita: resolve LL e a segunda metade de LR
}
if (bf < -1) { // Pesada à direita. Se o filho direito não é pesado à esquerda, é o caso RR
if (balanceFactor(n->getRight()) > 0) // O filho direito é pesado à esquerda: caso RL, girar à direita primeiro
n->setRight(rotateRight(n->getRight())); // Primeira rotação do caso RL
return rotateLeft(n); // Rotação à esquerda: resolve RR e a segunda metade de RL
}
return n; // O fator está entre -1 e 1: não é preciso rotacionar
}
Node* insert(Node* root, int v) { // Insere v na árvore AVL e devolve a raiz
if (root == nullptr) // Posição vazia: o novo nó fica aqui
return new Node(v); // Cria o novo nó
if (v < root->getValue()) // Valores menores vão para a esquerda e maiores para a direita
root->setLeft(insert(root->getLeft(), v)); // Desce pela subárvore esquerda
else
root->setRight(insert(root->getRight(), v)); // Desce pela subárvore direita
return rebalance(root); // Na volta de cada chamada, verifica-se o balanceamento do nó
}
int main() {
Node* root = buildTree(); // A árvore exibida, já construída
root = insert(root, v); // Primeira chamada, a partir de main
return 0; // Fim da operação
}

Esta ferramenta parte de uma árvore AVL aleatória, uma árvore binária de busca que se mantém balanceada, e permite modificá-la manualmente: digite um valor de 1 a 99 e clique em Inserir, Buscar ou Remover. Cada nó mostra seu fator de balanceamento, a diferença de altura entre suas subárvores, e seu índice no vetor. Quando um nó chega ao fator 2 ou -2, a animação o marca e aplica a rotação correta: LL, RR, LR ou RL. Abaixo, a mesma árvore aparece como um vetor e o código C++ destaca a linha em execução. Tudo é simulado no seu navegador.

Como usar

  1. Ajuste o tamanho da árvore com o controle deslizante ou clique em Gerar nova árvore para mudar o ponto de partida.
  2. Digite um valor de 1 a 99 e clique em Inserir, Buscar ou Remover; a animação começa sozinha.
  3. Observe o fator de balanceamento sob cada nó e a rotação aplicada quando ele chega a 2 ou -2.
  4. Avance ou volte e compare a árvore com sua forma de vetor e com a linha de C++ destacada.

Perguntas frequentes

O que é uma árvore AVL e o que ela garante?
É uma árvore binária de busca que se rebalanceia sozinha: em cada nó, a diferença entre a altura da subárvore esquerda e a da direita é de no máximo 1. Essa diferença é chamada de fator de balanceamento e vale -1, 0 ou 1 em uma AVL válida. Por isso, a altura cresce de forma logarítmica com o número de nós.
Quais são os quatro casos de rotação e quando se usa cada um?
Se um nó fica com fator 2 e seu filho esquerdo pende para a esquerda, é o caso LL e basta uma rotação simples à direita. Se o filho pende para a direita, é LR: o filho é rotacionado à esquerda e depois o nó à direita. Com fator -2 é simétrico: RR se resolve com uma rotação simples à esquerda e RL com uma rotação à direita do filho seguida de uma rotação à esquerda.
Quanto custam inserir, buscar e remover em comparação com uma BST?
Em uma AVL as três operações levam tempo logarítmico no pior caso, porque a altura nunca explode. Em uma BST simples o custo depende da altura, que pode se tornar linear se os valores forem inseridos em ordem e a árvore degenerar em uma lista. Em troca, a AVL realiza algumas rotações ao inserir ou remover.
Como uma AVL é armazenada em um vetor e qual é o índice acima de cada nó?
No formato de heap: a raiz fica no índice 0 e os filhos do índice i em 2i+1 e 2i+2. O número entre colchetes acima de cada nó é essa posição e corresponde à célula do vetor em que seu valor aparece. Se faltam filhos, as posições intermediárias ficam vazias.

Ferramentas relacionadas