Árvores binárias de pesquisa

Ordem global das subárvores, procura, inserção e remoção com sucessor.

TLDR

Perguntar sobre esta página

ChatGPTClaudePerplexityGrokGeminiCopiar e abrirDeepSeekCopiar e abrir

Numa árvore binária de pesquisa, ou BST, todas as chaves da subárvore esquerda são menores que a chave do nó e todas as da direita são maiores. Esta página usa chaves únicas. Outra política pode guardar um contador por chave, mas tem de ajustar inserção, remoção e tamanho.

Assume os percursos da página anterior e os intervalos semiabertos da pesquisa binária. A novidade é a ordem global mantida por rotações e limites herdados.

Invariante de ordem global

Não basta comparares um nó com os seus filhos diretos. Na árvore com raiz 8, filho esquerdo 4 e filho direito de 4 com chave 9, cada ligação pai-filho parece ordenada, mas 9 está na subárvore esquerda de 8 e viola o invariante.

Para validares, propaga limites abertos: a esquerda de x fica com limite superior x, e a direita fica com limite inferior x. Não uses x-1 e x+1 em inteiros extremos. Em cada nó, verifica a chave contra os limites herdados de todos os antepassados.

O percurso em-ordem visita chaves por ordem crescente: por hipótese indutiva, as duas subárvores produzem sequências crescentes; todas as chaves à esquerda vêm antes da raiz e todas à direita depois. O argumento depende da propriedade global.

Procurar e inserir

Compara o alvo com a raiz. Se for igual, encontraste. Se for menor, só a esquerda pode contê-lo; se maior, só a direita. Ao chegares ao vazio, a chave falta. A cada passo, o invariante é que qualquer ocorrência ainda possível está na subárvore atual.

Inserir segue o mesmo caminho até um filho vazio e cria aí uma folha. O percurso acumulou limites que a nova chave satisfaz, por isso a inserção conserva a ordem. Se encontrares uma chave igual, a política de conjunto não altera a árvore.

Inserir [8,3,12,1,6,10,14] cria uma árvore de altura 2. Procurar 6 visita 8, 3 e 6; procurar 5 visita 8, 3 e 6, depois o filho esquerdo vazio de 6. Encontrar o mínimo consiste em seguir filhos esquerdos; o máximo segue direitos.

O custo é O(h+1)O(h+1), com h a altura. Numa árvore equilibrada é O(log⁡(n+1))O(\log(n+1)); numa cadeia é O(n)O(n). Inserir chaves crescentes numa BST simples produz uma cadeia. A altura esperada é logarítmica com uma ordem de inserção uniformemente aleatória de chaves distintas; essa hipótese não é uma garantia para dados arbitrários.

Ordem de inserção e altura

Para um conjunto de n chaves distintas, a maior altura possível é n-1. Inserir por ordem crescente cria apenas filhos direitos; por ordem decrescente, apenas esquerdos. São duas maneiras de construir uma cadeia, sem alterar as regras da BST.

Para minimizar a altura, ordena as chaves e insere primeiro uma mediana; depois as medianas das duas metades, repetindo até inserir todas. Em [2,5,8,11,14,17,20], uma ordem possível é [11,5,17,2,8,14,20]. A árvore final tem altura 2, o mínimo, pois altura 1 só permite três nós. A ordem crescente dos mesmos sete valores dá altura 6.

O mínimo de uma BST não precisa de ser folha: não tem filho esquerdo, mas pode ter direito. Na cadeia crescente anterior, o mínimo 2 é a raiz e tem filho 5. A definição de mínimo exclui chaves menores, sem excluir chaves maiores abaixo dele.

Remover uma chave

Primeiro procura a chave. Se faltar, a árvore mantém-se. No nó encontrado, há três casos:

  1. Nenhum filho: substitui a ligação que chega ao nó por vazio e liberta-o.
  2. Um filho: substitui essa ligação pelo único filho e liberta o nó antigo. A subárvore continua dentro dos limites herdados.
  3. Dois filhos: encontra o sucessor, o mínimo da subárvore direita. Copia a sua chave, e o respetivo valor se existir, para o nó a remover; depois remove o sucessor da subárvore direita. Esse sucessor não tem filho esquerdo, pelo que a segunda remoção cai num caso simples.

Na árvore construída com [8,3,12,1,6,10,14], remover 8 substitui a raiz por 10, o mínimo da direita. A antiga folha 10 sai da esquerda de 12 e a em-ordem fica [1,3,6,10,12,14].

Para ver o caso em que o sucessor tem filho, considera outra árvore: raiz 3, filho esquerdo 1 e filho direito 8; 8 tem filho esquerdo 6, e 6 tem filho direito 7. Ao remover 3, copia 6 para a raiz e substitui 8.esquerdo por 7. A em-ordem final é [1,6,7,8]. Apagar o antigo 6 sem religar 7 perderia uma subárvore. Se usares o predecessor, o máximo da esquerda, a forma final pode diferir e continuar correta.

O sucessor é maior que todas as chaves da esquerda e não é maior que qualquer outra chave da direita. Por isso a substituição conserva a ordem global. O caminho para achar o sucessor e remover o nó continua limitado pela altura: tempo O(h+1)O(h+1), não O(h2)O(h^2).

Com multiplicidades, retirar uma ocorrência pode apenas reduzir o contador. Ao transplantares o sucessor, não deixes a mesma chave repartida por dois nós se o invariante usa comparações estritas. Uma remoção da raiz também tem de atualizar o apontador da raiz, não apenas um campo de um pai inexistente.

Limites, intervalos e biblioteca

O sucessor de uma chave tem dois casos: se existir subárvore direita, é o seu mínimo; caso contrário, é o primeiro antepassado em cujo ramo esquerdo está a chave. O predecessor é simétrico. A ausência de sucessor para o máximo é um resultado válido.

Para enumerares chaves num intervalo, descarta subárvores fora dos limites e visita em-ordem as restantes. Numa árvore equilibrada, uma consulta por intervalo com k resultados pode custar O(log⁡n+k)O(\log n+k). Fazer um percurso completo e filtrar custa O(n)O(n) e perde essa vantagem quando k é pequeno.

std::set representa um conjunto ordenado e std::map associa um valor a cada chave. Em ambos, pesquisa, inserção e remoção por chave têm custo logarítmico. map.find(chave) consulta sem inserir, ao contrário de map[chave], que cria um valor por omissão se a chave faltar.

multiset admite valores repetidos. Na ficha 08 (2025/26), count(valor) conta ocorrências e erase(valor) apaga todas. Para apagar só uma, passa a erase um iterador devolvido por find, depois de confirmares que não é end(). Com m ocorrências numa coleção de tamanho n, contar ou apagar todas custa O(log⁡n+m)O(\log n+m).

lower_bound(x) encontra o primeiro valor >=x e upper_bound(x) o primeiro >x; podem devolver end(). Percorrer o intervalo entre ambos conta os repetidos, mas os iteradores destas árvores não admitem subtração como os de um vetor. A equivalência é definida pelo comparador, não obrigatoriamente por operator==. O padrão garante os contratos e custos, sem exigir uma espécie concreta de árvore.

A comparação de chaves e a cópia dos valores contam. Com strings compridas, a análise de uma consulta pode incluir o custo de cada comparação.

Exercícios

As justificações e os programas em C++ são de autoavaliação. Compara o raciocínio com os critérios da solução.

Remover dois filhos com sucessor

Insere numa BST simples [9,4,13,2,7,11,15,10]. Remove 9 usando o sucessor. Dá a nova raiz e a em-ordem.

Pista

O sucessor é o mínimo da subárvore direita.

Mais uma pista

O caminho 13->11->10 encontra esse mínimo.

Solução

A nova raiz tem chave 10; retira a antiga folha 10 da esquerda de 11. A em-ordem é [2,4,7,10,11,13,15] e as restantes ligações não mudam. O sucessor é maior que toda a esquerda e menor que as restantes chaves da direita, por isso a ordem global conserva-se. O custo total é O(h+1).

Confere a tua resposta:

  • Escolhi 10, o mínimo da direita, como nova chave da raiz.
  • Retirei o nó antigo com 10, sem duplicar a chave.
  • Obtive em-ordem 2,4,7,10,11,13,15 e conservei a ordem global.

Erros frequentes

Não escolhas simplesmente o filho direito 13; não deixes duas cópias de 10 se a BST usa chaves únicas.

Voltar à explicação
Detetar uma ordem inválida

A raiz é 20, o filho esquerdo é 8 e o filho direito de 8 é 25. Os restantes filhos são vazios. É uma BST de chaves únicas? Justifica com limites.

Pista

O limite da raiz também se aplica a todos os descendentes esquerdos.

Mais uma pista

O nó 25 tem de estar no intervalo aberto (8,20).

Solução

Não é uma BST, porque 25 excede o limite superior 20 herdado. As comparações entre pai e filho isoladamente são insuficientes. Propagar limites abertos valida todos os nós em O(n), com espaço O(h+1) numa recursão.

Confere a tua resposta:

  • Rejeitei a árvore porque 25 está na esquerda de 20.
  • Propaguei ao nó 25 o intervalo aberto (8,20).
  • Distingui comparações locais da condição sobre toda a subárvore.

Erros frequentes

Não concluas validade só porque 8<20 e 25>8; evitar x+1 e x-1 também evita overflow nos limites extremos.

Voltar à explicação
Religar o filho do sucessor

Insere [3,1,8,6,7] numa BST vazia, com chaves únicas. Remove 3 usando o sucessor. Desenha a árvore antes e depois, mostra a ligação que evita perder 7 e dá a em-ordem final.

Pista
O sucessor não tem filho esquerdo.
Solução

Antes, 3 tem filhos 1 e 8; o filho esquerdo de 8 é 6, e 6 tem filho direito 7. O mínimo da direita de 3 é 6. Copia 6 para a raiz e substitui 8.esquerdo por 7 antes de libertar o antigo nó 6. Depois, a raiz 6 tem filhos 1 e 8, com 7 à esquerda de 8. A em-ordem é [1,6,7,8]. Perder 7 violaria a pós-condição de remover apenas 3, mesmo que a ordem entre os nós sobreviventes continuasse válida.

Confere a tua resposta:

  • Copiei o sucessor para o nó removido.
  • Liguei o filho direito do sucessor ao seu pai.
  • Verifiquei a em-ordem final.

Erros frequentes

Apagar o sucessor sem transplantar o filho direito perde uma subárvore.

Voltar à explicação
Construir a menor e a maior altura

Insere as chaves distintas {2,5,8,11,14,17,20} numa BST simples, inicialmente vazia. Dá uma ordem de inserção que maximize a altura e outra que a minimize, desenhando as ligações. Justifica os dois extremos. Na primeira árvore, o mínimo tem de estar numa folha?

Solução

Inserir [2,5,8,11,14,17,20] cria a cadeia direita com seis arestas, altura 6, o máximo para sete nós. O mínimo 2 é a raiz e tem filho direito, logo não é folha. Inserir [11,5,17,2,8,14,20] cria raiz 11, filhos 5 e 17, com folhas 2 e 8 sob 5, 14 e 20 sob 17. A altura é 2. Altura 1 só permite três nós; sete exigem pelo menos altura 2. Escolher medianas recursivamente e inserir cada raiz antes dos seus descendentes atinge esse limite.

Confere a tua resposta:

  • Construí uma cadeia de altura 6 e uma árvore de altura 2.
  • Justifiquei o mínimo pela capacidade de cada altura e insiro a raiz antes dos descendentes.
  • Mostrei que o mínimo pode ter filho direito e não ser folha.
Voltar à explicação

À tua maneira

Aparência

Modo de cor
Tema
Cor de destaque

Leitura

Fonte de leitura

Álgebra, lógica e uma ideia de cada vez.

Código

Fonte do código

Navegação

Cursor de leitura, sem edição. h, j, k, l movem; / pesquisa nesta página. v seleciona caracteres; V seleciona linhas; y copia. Tab permite destacar ou comentar. Espaço ou Enter abre blocos recolhíveis. Nos cartões, h, j, k, l mudam o foco.

CSS personalizado

Ativa uma sugestão ou guarda o teu CSS. Só muda este navegador.

Usa --page, --text e --accent para acompanhar o tema.

Seletores e recuperação

.site-header, .prose, .course-card, [data-reading-history], [data-playground] e .page-actions.

Abre a aparência com a tecla vírgula ou no rodapé. Se o CSS esconder os controlos, abre esta página sem CSS personalizado.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Copiar fórmula

A cópia automática não está disponível. Copia o LaTeX abaixo.

Pesquisar nesta página

Enter procura · n / N repetem · Esc cancela. Ctrl / Cmd K pesquisa todo o site.

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.