Menu
Coddy logo textTech

Árvore AVL

Última atualização

Uma árvore AVL é uma árvore binária de busca autobalanceada. Funciona como uma BST normal, mas após cada inserção verifica o fator de balanceamento de cada ancestral - a diferença de altura entre suas subárvores esquerda e direita - e se algum nó ficar desbalanceado (uma diferença maior que 1), realiza rotações para restaurar o balanceamento. Pressione reproduzir acima para ver os valores sendo inseridos e a árvore girar de volta à sua forma correta.

Como nunca deixa a árvore ficar mais do que levemente desequilibrada, uma árvore AVL garante altura O(log n), então busca, inserção e remoção são sempre O(log n) - mesmo para entradas ordenadas que arruinariam uma BST comum. O custo são as rotações extras e o controle de altura em cada inserção.

Complexidade de tempo e espaço

OperaçãoComplexidadeNotas
BuscaO(log n)A altura é sempre ~1.44 log n
InserçãoO(log n)Mais O(1) rotações
RemoçãoO(log n)Mais O(log n) rotações
EspaçoO(n)Um campo de altura por nó

Os quatro casos de rotação

CasoDesbalanceamentoCorreção
Esquerda-EsquerdaPesado na esquerda do filho esquerdoUma rotação à direita
Direita-DireitaPesado na direita do filho direitoUma rotação à esquerda
Esquerda-DireitaPesado na direita do filho esquerdoRotação à esquerda e depois à direita
Direita-EsquerdaPesado na esquerda do filho direitoRotação à direita e depois à esquerda

Exemplo resolvido

Inserindo [10, 20, 30, 40, 50, 25] um valor de cada vez:

PassoEstruturaAção
Inserir 1010O primeiro nó se torna a raiz; balanceado
Inserir 2010(_, 20)Vai à direita de 10; ainda balanceado
Inserir 3020(10, 30)Direita-Direita em 10, então uma rotação à esquerda eleva 20 à raiz
Inserir 4020(10, 30(_, 40))Vai à direita de 30; todos os fatores de balanceamento ficam dentro de ±1
Inserir 5020(10, 40(30, 50))Direita-Direita em 30, então uma rotação à esquerda em 30 eleva 40
Inserir 2530(20(10, 25), 40(_, 50))Direita-Esquerda em 20: rotaciona à direita a subárvore de 40 e depois rotaciona à esquerda 20

Quando usar uma árvore AVL

Use quandoEvite quando
As buscas superam em muito as inserções e você quer a altura mais compacta possívelInserções e remoções dominam - as rotações e o rebalanceamento extras custam mais do que numa árvore rubro-negra
Você precisa de pior caso garantido O(log n), mesmo para entradas adversárias ou ordenadasUma tabela hash simples bastaria - você não precisa de percurso ordenado nem consultas por intervalo
Você precisa de operações ordenadas: percurso em ordem, predecessor/sucessor, consultas por intervaloO conjunto de dados é minúsculo - uma BST comum ou um array ordenado é mais simples e rápido o suficiente
Os dados podem chegar já ordenados, o que transformaria uma BST não balanceada numa lista encadeadaVocê não pode arcar com a memória extra do campo de altura por nó num espaço muito restrito

Código de AVL Tree

Uma implementação limpa e executável de AVL Tree em Python, JavaScript, Java, C++, C. Escolha uma linguagem, copie o código ou abra-o já carregado no Playground da Coddy.

Código de AVL Tree em Python

Python
1class Node:2    def __init__(self, key):3        self.key = key4        self.left = None5        self.right = None6        self.height = 17
8
9def height(node):10    return node.height if node else 011
12
13def update(node):14    node.height = 1 + max(height(node.left), height(node.right))15
16
17def rotate_right(y):18    x = y.left19    y.left = x.right20    x.right = y21    update(y)22    update(x)23    return x24
25
26def rotate_left(x):27    y = x.right28    x.right = y.left29    y.left = x30    update(x)31    update(y)32    return y33
34
35def insert(node, key):36    if node is None:37        return Node(key)38    if key < node.key:39        node.left = insert(node.left, key)40    else:41        node.right = insert(node.right, key)42    update(node)43    balance = height(node.left) - height(node.right)44    # Four imbalance cases: LL, RR, LR, RL45    if balance > 1 and key < node.left.key:46        return rotate_right(node)47    if balance < -1 and key > node.right.key:48        return rotate_left(node)49    if balance > 1:50        node.left = rotate_left(node.left)51        return rotate_right(node)52    if balance < -1:53        node.right = rotate_right(node.right)54        return rotate_left(node)55    return node56
57
58def inorder(node):59    if node is None:60        return []61    return inorder(node.left) + [node.key] + inorder(node.right)62
63
64root = None65for key in [10, 20, 30, 40, 50, 25]:66    root = insert(root, key)67
68print("Inorder:", inorder(root))69print("Root:", root.key, "| tree height:", root.height)
Execute este código no Playground de Python

Perguntas frequentes sobre a árvore AVL

O que é um fator de balanceamento numa árvore AVL?
O fator de balanceamento de um nó é a altura de sua subárvore esquerda menos a altura de sua subárvore direita. Uma árvore AVL mantém o fator de balanceamento de cada nó em -1, 0 ou +1; se uma inserção o tira desse intervalo, uma rotação restaura o balanceamento.
Qual é a diferença entre uma árvore AVL e uma árvore rubro-negra?
Ambas são BSTs autobalanceadas com operações O(log n). As árvores AVL são mais estritamente balanceadas, então as buscas são ligeiramente mais rápidas, mas podem fazer mais rotações na inserção/remoção. As árvores rubro-negras são mais frouxamente balanceadas, favorecendo menos rotações - por isso muitas bibliotecas padrão as usam para mapas e conjuntos.
Por que usar uma árvore AVL em vez de uma árvore binária de busca comum?
Uma BST comum pode degradar para operações O(n) se os valores chegarem em ordem, formando uma cadeia enviesada. Uma árvore AVL rotaciona para permanecer balanceada, garantindo altura e operações O(log n) independentemente da ordem de inserção.
Uma árvore AVL é melhor que uma árvore rubro-negra para um índice de banco de dados?
Depende da carga de trabalho. As árvores AVL são mais rigidamente balanceadas, então vencem quando as leituras dominam e você quer os caminhos de busca mais curtos possíveis. Mas a maioria dos bancos de dados e bibliotecas de linguagens escolhe árvores rubro-negras (ou árvores B) porque rebalanceiam com menos rotações em cargas com muitas escritas, o que importa mais quando inserções e remoções são frequentes.
Quantas rotações uma única inserção AVL precisa?
É necessária no máximo uma rotação - seja uma rotação simples ou uma dupla (de dois passos) - para rebalancear a árvore após inserir um valor. Isso ocorre porque uma inserção aumenta a altura de uma subárvore em no máximo um, então uma única correção no ancestral desbalanceado mais baixo basta. A remoção é diferente: pode exigir até O(log n) rotações à medida que o rebalanceamento se propaga em direção à raiz.
Preciso atualizar as alturas dos nós após cada rotação?
Sim - um erro comum é rotacionar os ponteiros corretamente mas esquecer de recalcular a altura dos dois nós envolvidos. Após cada rotação você deve atualizar primeiro a altura do nó rebaixado e depois a do nó promovido, porque a altura do nó promovido depende de seus novos filhos. Omitir isso deixa fatores de balanceamento desatualizados que quebram as decisões de rebalanceamento futuras.
Coddy programming languages illustration

Domine algoritmos com a Coddy

COMEÇAR