Skip to content

Árvore Binária de Busca (BST) - Implementação Avançada


1. Conceitos Gerais

Uma Árvore Binária de Busca (BST) é uma estrutura de dados que permite a busca binária a partir da raiz, mantendo os elementos organizados de forma hierárquica com base em suas chaves.

Princípio fundamental: Para qualquer nó: - Todos os nós na subárvore esquerda têm chaves menores; - Todos os nós na subárvore direita têm chaves maiores;


2. Estrutura de Dados

2.1 Definições e Macros

Definições básicas para BST:
typedef int Key;  // Tipo da chave

// Estrutura do item (chave + dados)
typedef struct {
    Key k;        // Chave
    // data d;    // Dados associados (pode ser expandido)
} Item;

#define NULL_ITEM {0}  // Item nulo

// Macros para manipulação de itens
#define key(A) ((A).k)
#define less(A, B) (key(A) < key(B))
#define eq(A, B) (key(A) == key(B))

2.2 Estrutura do Nó

Estrutura do nó da BST:
typedef struct STNode *link;

struct STNode {
    Item item;    // Item armazenado
    link l;       // Ponteiro para filho esquerdo
    link r;       // Ponteiro para filho direito
    int N;        // Tamanho da subárvore (nó atual + filhos)
};

// Variáveis globais
link h;  // Raiz da árvore
link z;  // Nó sentinela (representa folhas vazias/nulo)

3. Implementação das Operações

3.1 Inicialização e Utilidades

Inicialização e funções auxiliares:
// Criar um novo nó
link NEW(Item item, link l, link r, int N) {
    link x = malloc(sizeof(struct STNode));
    x->item = item;
    x->l = l;
    x->r = r;
    x->N = N;
    return x;
}

// Inicializar a árvore
void ST_init() {
    z = NEW(NULL_ITEM, NULL, NULL, 0);  // Nó sentinela
    h = z;  // Raiz inicial aponta para sentinela
}

// Retorna o número de nós da árvore
int ST_count() {
    return h->N;
}

// Verifica se a árvore está vazia
int ST_empty() {
    return h == z;
}

3.2 Inserção

Inserção recursiva:
// Função pública de inserção
void ST_insert(Item item) {
    h = insertR(h, item);
}

// Função recursiva de inserção
link insertR(link r, Item item) {
    if (r == z)  // Encontrou posição de inserção
        return NEW(item, z, z, 1);

    Key k = key(item);
    Key t = key(r->item);

    if (less(k, t)) {
        r->l = insertR(r->l, item);
    } else {
        r->r = insertR(r->r, item);
    }

    r->N++;  // Atualiza contador de nós
    return r;
}

3.3 Busca

Busca recursiva:
// Função pública de busca
Item ST_search(Key k) {
    return searchR(h, k);
}

// Função recursiva de busca
Item searchR(link r, Key k) {
    if (r == z)  // Não encontrado
        return NULL_ITEM;

    Key t = key(r->item);

    if (eq(k, t))
        return r->item;
    else if (less(k, t))
        return searchR(r->l, k);
    else
        return searchR(r->r, k);
}

3.4 Travessia e Ordenação

Travessia in-order (ordenada):
// Função de visita (pode ser personalizada)
void visit(Item i) {
    printf("%d ", key(i));  // Exemplo: imprime a chave
}

// Travessia in-order recursiva
void sortR(link r, void (*visit)(Item)) {
    if (r == z) return;

    sortR(r->l, visit);  // Visita subárvore esquerda
    visit(r->item);      // Visita nó atual
    sortR(r->r, visit);  // Visita subárvore direita
}

// Função pública para ordenação
void ST_sort(void (*visit)(Item)) {
    sortR(h, visit);
}

3.5 Exemplo de Uso

Exemplo de uso da BST:
int main() {
    ST_init();  // Inicializa árvore

    // Insere alguns itens
    Item items[] = {{5}, {3}, {7}, {2}, {4}, {6}, {8}};
    for (int i = 0; i < 7; i++) {
        ST_insert(items[i]);
    }

    printf("Número de nós: %d\n", ST_count());
    printf("Elementos em ordem: ");
    ST_sort(visit);  // Imprime: 2 3 4 5 6 7 8

    // Busca por uma chave
    Key busca = 4;
    Item resultado = ST_search(busca);
    if (key(resultado) != 0) {
        printf("\nEncontrado: %d\n", key(resultado));
    } else {
        printf("\nNão encontrado: %d\n", busca);
    }

    return 0;
}

4. Análise de Performance

4.1 Complexidade das Operações

Operação Melhor Caso Caso Médio Pior Caso
Busca O(1) O(log n) O(n)
Inserção O(1) O(log n) O(n)
Remoção O(1) O(log n) O(n)
Travessia O(n) O(n) O(n)

4.2 Propriedades Estatísticas

  • Busca bem-sucedida: ≈1.39 log₂N comparações em média;
  • Busca mal-sucedida: ≈1.39 log₂N comparações em média;
  • Altura média: ≈1.39 log₂N para árvores aleatórias;

4.3 Problemas e Limitações

  • Desbalanceamento: Inserções ordenadas criam árvores degeneradas (lista encadeada);
  • Performance no pior caso: Operações tornam-se O(n);
  • Memória: Overhead de ponteiros e contadores;

5. Considerações Finais

5.1 Quando Usar BST

  • Dados dinâmicos: Inserções e remoções frequentes;
  • Busca ordenada: Necessidade de percurso ordenado;
  • Memória disponível: Overhead aceitável de ponteiros;

5.2 Alternativas

  • Hash Tables: Melhor para busca exata (O(1) average);
  • Arrays ordenados: Melhor para dados estáticos;
  • Árvores balanceadas: AVL, Red-Black, B-Trees para grandes datasets;