Depois de tanta teoria e código, vamos testar nossa Árvore Binária de Busca Balanceada, nossa Árvore AVL?
Aqui você encontra todo o código apresentado nas aulas anteriores.
Caso tenha perdido alguma aula sobre a Árvore AVL, deixarei aqui o link para as aulas anteriores:
O que é uma Arvore AVL – Árvore Binária de Busca Balanceada?
Como implementar uma Árvore AVL – Árvore balanceada?
Como implementar uma ROTAÇÃO À ESQUERDA em uma árvore AVL?
Como implementar uma ROTAÇÃO À DIREITA em uma árvore AVL?
Como implementar as ROTAÇÕES DUPLAS em uma árvore AVL?
Como inserir em uma árvore binária balanceada – Árvore AVL?
Como remover um nó em uma árvore binária balanceada – Árvore AVL?
Como imprimir uma Árvore Binária Balanceada – Árvore AVL?
Código de exemplo completo em C para uma Árvore Binária de Busca Balanceada – Árvore AVL
#include <stdio.h>
#include <stdlib.h>
typedef struct no{
int valor;
struct no *esquerdo, *direito;
short altura;
}No;
/*
Função que cria um novo nó
x -> valor a ser inserido no nó
Retorna: o endereço do nó criado
*/
No* novoNo(int x){
No *novo = malloc(sizeof(No));
if(novo){
novo->valor = x;
novo->esquerdo = NULL;
novo->direito = NULL;
novo->altura = 0;
}
else
printf("\nERRO ao alocar nó em novoNo!\n");
return novo;
}
/*
Retorna o maior dentre dois valores
a, b -> altura de dois nós da árvore
*/
short maior(short a, short b){
return (a > b)? a: b;
}
// Retorna a altura de um nó ou -1 caso ele seja null
short alturaDoNo(No *no){
if(no == NULL)
return -1;
else
return no->altura;
}
// Calcula e retorna o fator de balanceamento de um nó
short fatorDeBalanceamento(No *no){
if(no)
return (alturaDoNo(no->esquerdo) - alturaDoNo(no->direito));
else
return 0;
}
// --------- ROTAÇÕES ---------------------------
// função para a rotação à esquerda
No* rotacaoEsquerda(No *r){
No *y, *f;
y = r->direito;
f = y->esquerdo;
y->esquerdo = r;
r->direito = f;
r->altura = maior(alturaDoNo(r->esquerdo), alturaDoNo(r->direito)) + 1;
y->altura = maior(alturaDoNo(y->esquerdo), alturaDoNo(y->direito)) + 1;
return y;
}
// função para a rotação à direita
No* rotacaoDireita(No *r){
No *y, *f;
y = r->esquerdo;
f = y->direito;
y->direito = r;
r->esquerdo = f;
r->altura = maior(alturaDoNo(r->esquerdo), alturaDoNo(r->direito)) + 1;
y->altura = maior(alturaDoNo(y->esquerdo), alturaDoNo(y->direito)) + 1;
return y;
}
No* rotacaoEsquerdaDireita(No *r){
r->esquerdo = rotacaoEsquerda(r->esquerdo);
return rotacaoDireita(r);
}
No* rotacaoDireitaEsquerda(No *r){
r->direito = rotacaoDireita(r->direito);
return rotacaoEsquerda(r);
}
/*
Função para realizar o balanceamento da árvore após uma inserção ou remoção
Recebe o nó que está desbalanceado e retorna a nova raiz após o balanceamento
*/
No* balancear(No *raiz){
short fb = fatorDeBalanceamento(raiz);
// Rotação à esquerda
if(fb < -1 && fatorDeBalanceamento(raiz->direito) <= 0)
raiz = rotacaoEsquerda(raiz);
// Rotação à direita
else if(fb > 1 && fatorDeBalanceamento(raiz->esquerdo) >= 0)
raiz = rotacaoDireita(raiz);
// Rotação dupla à esquerda
else if(fb > 1 && fatorDeBalanceamento(raiz->esquerdo) < 0)
raiz = rotacaoEsquerdaDireita(raiz);
// Rotação dupla à direita
else if(fb < -1 && fatorDeBalanceamento(raiz->direito) > 0)
raiz = rotacaoDireitaEsquerda(raiz);
return raiz;
}
/*
Insere um novo nó na árvore
raiz -> raiz da árvore
x -> valor a ser inserido
Retorno: endereço do novo nó ou nova raiz após o balanceamento
*/
No* inserir(No *raiz, int x){
if(raiz == NULL) // árvore vazia
return novoNo(x);
else{ // inserção será à esquerda ou à direita
if(x < raiz->valor)
raiz->esquerdo = inserir(raiz->esquerdo, x);
else if(x > raiz->valor)
raiz->direito = inserir(raiz->direito, x);
else
printf("\nInsercao nao realizada!\nO elemento %d a existe!\n", x);
}
// Recalcula a altura de todos os nós entre a raiz e o novo nó inserido
raiz->altura = maior(alturaDoNo(raiz->esquerdo), alturaDoNo(raiz->direito)) + 1;
// verifica a necessidade de rebalancear a árvore
raiz = balancear(raiz);
return raiz;
}
/*
Função para remover um nó da Árvore binária balanceada
Pode ser necessário rebalancear a árvore e a raiz pode ser alterada
por isso precisamos retornar a raiz
*/
No* remover(No *raiz, int chave) {
if(raiz == NULL){
printf("Valor nao encontrado!\n");
return NULL;
} else { // procura o nó a remover
if(raiz->valor == chave) {
// remove nós folhas (nós sem filhos)
if(raiz->esquerdo == NULL && raiz->direito == NULL) {
free(raiz);
printf("Elemento folha removido: %d !\n", chave);
return NULL;
}
else{
// remover nós que possuem 2 filhos
if(raiz->esquerdo != NULL && raiz->direito != NULL){
No *aux = raiz->esquerdo;
while(aux->direito != NULL)
aux = aux->direito;
raiz->valor = aux->valor;
aux->valor = chave;
printf("Elemento trocado: %d !\n", chave);
raiz->esquerdo = remover(raiz->esquerdo, chave);
return raiz;
}
else{
// remover nós que possuem apenas 1 filho
No *aux;
if(raiz->esquerdo != NULL)
aux = raiz->esquerdo;
else
aux = raiz->direito;
free(raiz);
printf("Elemento com 1 filho removido: %d !\n", chave);
return aux;
}
}
} else {
if(chave < raiz->valor)
raiz->esquerdo = remover(raiz->esquerdo, chave);
else
raiz->direito = remover(raiz->direito, chave);
}
// Recalcula a altura de todos os nós entre a raiz e o novo nó inserido
raiz->altura = maior(alturaDoNo(raiz->esquerdo), alturaDoNo(raiz->direito)) + 1;
// verifica a necessidade de rebalancear a árvore
raiz = balancear(raiz);
return raiz;
}
}
void imprimir(No *raiz, int nivel){
int i;
if(raiz){
imprimir(raiz->direito, nivel + 1);
printf("\n\n");
for(i = 0; i < nivel; i++)
printf("\t");
printf("%d", raiz->valor);
imprimir(raiz->esquerdo, nivel + 1);
}
}
int main(){
int opcao, valor;
No *raiz = NULL;
do{
printf("\n\n\t0 - Sair\n\t1 - Inserir\n\t2 - Remover\n\t3 - Imprimir\n\n");
scanf("%d", &opcao);
switch(opcao){
case 0:
printf("Saindo!!!");
break;
case 1:
printf("\tDigite o valor a ser inserido: ");
scanf("%d", &valor);
raiz = inserir(raiz, valor);
break;
case 2:
printf("\tDigite o valor a ser removido: ");
scanf("%d", &valor);
raiz = remover(raiz, valor);
break;
case 3:
imprimir(raiz, 1);
break;
default:
printf("\nOcao invalida!!!\n");
}
}while(opcao != 0);
return 0;
}
