Árvore binária AVL
Publicado por Caio Dutra (última atualização em 23/01/2010)
[ Hits: 47.725 ]
Está aí a estrutura de uma árvore AVL.
Abraço!
/* ---------------------------------------------------------------- avl_tree.h
AVL Tree - Caio Dutra <caiodutra@uft.edu.br>
UFT - EDII - 01/2010
Biblioteca relativa a estrutura de dados. Caracteriza aqui a Árvore AVL.
----> Por convenção, todos as funções listadas neste arquivo referentes a
manipulação de árvore AVL terão o prefixo avl_, para evitar possíveis
conflitos de nomes.
---------------------------------------------------------------------------*/
#ifndef AVL_H
#define AVL_H
#ifdef __cplusplus
exterm "C" {
#endif
typedef struct AVL_Node
{
/*
* Estrutura do nó da árvore AVL.
* Contém um bit extra que informa
* o grau de balanceamento da árvore.
* Se for 0, 1 ou -1, a árvore está
* balanceada. Se não, serão realizadas
* algumas mudanças até que se balanceie
*/
void *info; // Informação contida no nó
int bal; // Fator de balanceamento do nó
struct AVL_Node *pai; // Aponta para o nó ancestral
struct AVL_Node *esq; // Aponta para o filho da esquerda
struct AVL_Node *dir; // Aponta para o filho da direita
} AVL_Node;
typedef struct AVL_Tree
{
/*
* Estrutura que define a árvore AVL.
* Aonde está guardada a raiz da árvore.
* Contém ponteiros para funções que
* manipulam as informações contidas na
* árvore.
*
* A função que o ponteiro compara_info
* aponta deverá retornar um valor inteiro
* segundo a seguinte legenda:
* +1 => Se o primeiro for maior
* -1 => Se o segundo for maior
* 0 => Se os dois forem iguais
*/
AVL_Node *root; // Raiz da árvore
unsigned int num_nodes; // Número de nós da árvore
// Função que compara duas informações
int (*compara_info)( const void *, const void * );
// Função que imprime uma informação
void (*imprime_info)( const void * );
} AVL_Tree;
/* Funções para manipulação da árvore */
// Inicialização da árvore
void avl_init ( AVL_Tree **, int (*compara_info)( const void *, const void * ),
void (*imprime_info)( const void * ));
// Insere um elemento na árvore
int avl_insert ( AVL_Tree **, AVL_Node *, AVL_Node **, void * );
// Remove um elemento da árvore
int avl_remove ( AVL_Tree **, AVL_Node **, void * );
// Realiza o percurso em pré-ordem
void avl_walk_pre ( AVL_Tree *, AVL_Node * );
// Realiza o percurso em pos-ordem
void avl_walk_pos ( AVL_Tree *, AVL_Node * );
// Realiza o percurso em ordem simetrica
void avl_walk_sim ( AVL_Tree *, AVL_Node * );
// Realiza o percurso na árvore por nível
void avl_walk_byLevel ( AVL_Tree * );
// Faz uma busca na árvore
AVL_Node *avl_search ( AVL_Tree *, AVL_Node *, void * );
// Retorna a altura de uma sub-árvore
int avl_height ( AVL_Node * );
#ifdef __cplusplus
}
#endif
#endif /* AVL_H */
/* ---------------------------------------------------------------- avl_tree.c
AVL Tree API - Caio Dutra <caiodutra@uft.edu.br>
UFT - EDII - 01/2010
Biblioteca relativa a estrutura de dados. Caracteriza aqui a Árvore AVL.
----> Por convenção, todos as funções listadas neste arquivo referentes a
manipulação de árvore AVL terão o prefixo avl_, para evitar possíveis
conflitos de nomes.
---------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include "avl_tree.h"
void avl_init ( AVL_Tree **tree,
int (*compara_info)( const void *, const void *),
void (*imprime_info)( const void * ))
/* Inicializa a árvore */
{
AVL_Tree *nova;
nova = ( AVL_Tree * ) malloc ( sizeof ( AVL_Tree ));
if ( nova == NULL ) return;
nova->root = NULL;
nova->num_nodes = 0;
nova->compara_info = compara_info;
nova->imprime_info = imprime_info;
*tree = nova;
}
int avl_height ( AVL_Node *node ) {
int esq, dir;
if ( node == NULL ) return -1;
esq = avl_height ( node->esq );
dir = avl_height ( node->dir );
if ( esq > dir )
return esq + 1;
else
return dir + 1;
}
/* -- Rotações de sub-árvore --
*
* A árvore AVL necessita, além das rotinas
* básicas, algumas rotinas auxiliares para
* mantê-la balanceada. São elas: rotação
* simples para a esquerda, rotação simples
* para a direita.
*/
AVL_Node *rotacao_direita ( AVL_Node *p )
/* Rotação simples para a direita */
{
AVL_Node *q;
q = p->esq;
//----------------> Realiza a rotação
p->esq = q->dir;
if ( q->dir != NULL )
q->dir->pai = p;
q->dir = p;
q->pai = p->pai;
if ( p->pai != NULL )
if ( p->pai->esq == p )
p->pai->esq = q;
else
p->pai->dir = q;
p->pai = q;
//----------------> Rebalanceia
q->bal = avl_height ( q->dir ) - avl_height ( q->esq );
p->bal = avl_height ( p->dir ) - avl_height ( p->esq );
return q;
}
AVL_Node *rotacao_esquerda ( AVL_Node *p )
/* Rotação simples para a esquerda */
{
AVL_Node *q;
q = p->dir;
//----------------> Realiza a rotação
p->dir = q->esq;
if ( q->esq != NULL )
q->esq->pai = p;
q->esq = p;
q->pai = p->pai;
if ( p->pai != NULL )
if ( p->pai->esq == p )
p->pai->esq = q;
else
p->pai->dir = q;
p->pai = q;
//----------------> Rebalanceia
q->bal = avl_height ( q->dir ) - avl_height ( q->esq );
p->bal = avl_height ( p->dir ) - avl_height ( p->esq );
return q;
}
/* Inserção na árvore AVL */
int avl_insert ( AVL_Tree **tree, AVL_Node *pai, AVL_Node **node, void *info )
{
AVL_Node *novo;
int aux;
if ( *tree == NULL ) return -1;
if ( *node == NULL )
// Se for o local correto para a inserção
{
novo = ( AVL_Node * ) malloc ( sizeof ( AVL_Node ));
if ( novo == NULL ) return -1;
novo->info = info;
novo->bal = 0;
novo->pai = pai;
novo->esq = NULL;
novo->dir = NULL;
*node = novo;
(*tree)->num_nodes++;
return 1;
}
/*
* Procura o local apropriado. Na volta da pilha do processador, o
* algoritmo vai atualizando o fator de balanceamento de cada nó.
* São feitas rotações, se necessárias, para que a árvore se rebalanceie.
*/
if ( (*tree)->compara_info( info, (*node)->info ) == +1 ) {
aux = avl_insert ( tree, *node, &((*node)->dir), info );
if ( aux != 1 ) return 0;
if ( ++((*node)->bal) == 2 ) {
if ( (*node)->dir->bal == 1 ) {
*node = rotacao_esquerda ( *node );
return 0;
}
(*node)->dir = rotacao_direita ( (*node)->dir );
*node = rotacao_esquerda ( *node );
return 0;
}
return ( (*node)->bal == 0 )? 0: 1;
}
if ( (*tree)->compara_info( info, (*node)->info ) == -1 ) {
aux = avl_insert ( tree, *node, &((*node)->esq), info );
if ( aux != 1 ) return 0;
if ( --((*node)->bal) == -2 ) {
if ( (*node)->esq->bal == -1 ) {
*node = rotacao_direita ( *node );
return 0;
}
(*node)->esq = rotacao_esquerda ( (*node)->esq );
*node = rotacao_direita ( *node );
return 0;
}
return ( (*node)->bal == 0 )? 0: 1;
}
return 0;
}
/* Remove um elemento da árvore */
int avl_remove ( AVL_Tree **tree, AVL_Node **node, void *info )
{
int ret;
if ( *node == NULL || *tree == NULL ) return -1;
if ( (*tree)->compara_info( info, (*node)->info ) == +1 )
// Vai para a S.A. da esquerda
{
ret = avl_remove ( tree, &((*node)->dir), info );
if ( ret != 1 ) return 0;
if ( --((*node)->bal) == -2 ) {
if ( (*node)->esq->bal == -1 ) {
*node = rotacao_direita ( *node );
return 0;
}
(*node)->esq = rotacao_esquerda ( (*node)->esq );
*node = rotacao_direita ( *node );
return 0;
}
return ( (*node)->bal == 0 )? 1: 0;
}
if ( (*tree)->compara_info( info, (*node)->info ) == -1 )
// Vai para a S.A. da direita
{
ret = avl_remove ( tree, &((*node)->esq), info );
if ( ret != 1 ) return 0;
if ( ++((*node)->bal) == +2 ) {
if ( (*node)->dir->bal == 1 ) {
*node = rotacao_esquerda ( *node );
return 0;
}
(*node)->dir = rotacao_direita ( (*node)->dir );
*node = rotacao_esquerda ( *node );
return 0;
}
return ( (*node)->bal == 0 )? 1: 0;
}
if ( (*tree)->compara_info( info, (*node)->info ) == 0 )
// Encontrou o elemento a ser removido
{
AVL_Node *aux, *temp;
void *i;
if ( (*node)->esq == NULL ) {
if ( (*node)->dir == NULL )
// Se não contiver filho algum
{
free ( *node );
*node = NULL;
(*tree)->num_nodes--;
return 1;
}
// Se contiver o filho da direita
aux = *node;
temp = (*node)->dir;
temp->pai = (*node)->pai;
if ( (*node)->pai != NULL )
if ( (*node)->pai->esq == *node )
(*node)->pai->esq = temp;
else
(*node)->pai->dir = temp;
*node = temp;
free ( aux );
(*tree)->num_nodes--;
return 1;
}
if ( (*node)->dir == NULL )
// Se contiver apenas o filho da esquerda
{
aux = *node;
temp = (*node)->esq;
temp->pai = (*node)->pai;
if ( (*node)->pai != NULL )
if ( (*node)->pai->esq == *node )
(*node)->pai->esq = temp;
else
(*node)->pai->dir = temp;
*node = temp;
free ( aux );
(*tree)->num_nodes--;
return 1;
}
// Se contiver os dois filhos
aux = (*node)->esq;
while ( aux->dir != NULL )
aux = aux->dir;
i = aux->info;
avl_remove ( tree, node, aux->info );
(*node)->info = i;
return 1;
}
}
/* Percursos da árvore */
void avl_walk_pre ( AVL_Tree *tree, AVL_Node *node )
// Percorre a árvore em pré-ordem
{
if ( node == NULL ) return;
tree->imprime_info( node->info );
if ( node->esq != NULL && node->dir != NULL ) printf ( ", " );
avl_walk_pre ( tree, node->esq );
avl_walk_pre ( tree, node->dir );
}
void avl_walk_pos ( AVL_Tree *tree, AVL_Node *node )
// Percorre a árvore em pós-ordem
{
if ( node == NULL ) return;
avl_walk_pre ( tree, node->esq );
avl_walk_pre ( tree, node->dir );
tree->imprime_info( node->info );
if ( node->esq != NULL && node->dir != NULL ) printf ( ", " );
}
void avl_walk_sim ( AVL_Tree *tree, AVL_Node *node )
// Percorre a árvore em ordem simétrica
{
if ( node == NULL ) return;
avl_walk_pre ( tree, node->esq );
tree->imprime_info( node->info );
if ( node->esq != NULL && node->dir != NULL ) printf ( ", " );
avl_walk_pre ( tree, node->dir );
}
void avl_walk_lev ( AVL_Tree *tree )
// Percorre a árvore por nível ( Busca Lateral )
{
AVL_Node *queue[tree->num_nodes];
AVL_Node *aux;
int tail = -1, i;
if ( tree->root == NULL ) return;
queue[++tail] = tree->root;
while ( tail > -1 ) {
aux = queue[0];
for ( i = 0; i < tail; i++ )
queue[i] = queue[i+1];
tail--;
tree->imprime_info( aux->info );
printf ( " " );
if ( aux->esq != NULL )
queue[++tail] = aux->esq;
if ( aux->dir != NULL )
queue[++tail] = aux->dir;
}
}
void avl_print ( AVL_Tree *tree, AVL_Node *node, int level )
{
int i;
if ( tree == NULL || node == NULL ) return;
for ( i = 0; i < level; i++ )
printf ( " " );
printf ( "> [" );
tree->imprime_info( node->info );
printf ( "][%i]\n", node->bal );
avl_print ( tree, node->esq, level + 1 );
avl_print ( tree, node->dir, level + 1 );
}
/* Busca por um elemento */
AVL_Node *avl_search ( AVL_Tree *tree, AVL_Node *node, void *info )
{
if ( tree == NULL || node == NULL ) return NULL;
if ( tree->compara_info( info, node->info ) == 0 ) return node;
if ( tree->compara_info( info, node->info ) > 0 )
return avl_search ( tree, node->dir, info );
else
return avl_search ( tree, node->esq, info );
}
Sistema básico de cadastro usando Listas Encadeadas
Monitorando o Preço do Bitcoin ou sua Cripto Favorita em Tempo Real com um Widget Flutuante
IA Turbina o Desktop Linux enquanto distros renovam forças
Como extrair chaves TOTP 2FA a partir de QRCODE (Google Authenticator)
Como realizar um ataque de força bruta para desobrir senhas?
Como usar Gpaste no ambiente Cinnamon
Atualizando o Fedora 42 para 43
ERRO: LAZARUS 4.2 64 no Linux MINT não entra mais apos ajustar desktop... (0)
Pergunta: Meu teclado não está respondendo direito como e consertar? (2)
Secure boot, artigo interessante, nada técnico. (6)
SQLITE não quer funcionar no LINUX LMDE6 64 com Lazaruz 4.2 64bit (n... (0)









