#include <stdio.h>
#include <stdlib.h>
//Criação da estrutura de um nó da arvore
struct No{
int num; //Número armazenado
int fb; //Fator de balanceamento
struct No* L; //Filho à esquerda
struct No* R; //Filho à direita
};
typedef struct No No;
/*
UTILIZANDO PONTEIRO DUPLO
**pRaiz == ARVORE
pRaiz->num == Resulta em ERRO pois a ARVORE em si não possui um número, apenas os nós
Para acessar os atributos é preciso referenciar o NÓ e não a ARVORE
*pRaiz = Nó
(*pRaiz)->num == Correto para acessar um atributo de um nó
*/
/* Define o primeiro NÓ da ARVORE como nulo */
void criarArvore(No **pRaiz){
*pRaiz = NULL;
}
/*Mostra os números recursivamente*/
void showRED(No **pRaiz){
if((*pRaiz) != NULL){
printf("%d - ",(*pRaiz)->num); /*R*/
showRED(&(*pRaiz)->L); /*E*/
showRED(&(*pRaiz)->R); /*D*/
}
}
void showERD(No **pRaiz){
if((*pRaiz) != NULL){
showERD(&(*pRaiz)->L);
printf("%d(%d) - ",(*pRaiz)->num,(*pRaiz)->fb);
showERD(&(*pRaiz)->R);
}
}
void showEDR(No **pRaiz){
if((*pRaiz) != NULL){
showEDR(&(*pRaiz)->L);
showEDR(&(*pRaiz)->R);
printf("%d - ",(*pRaiz)->num);
}
}
/*Busca o nó que possui o número 'n' salvo*/
No* buscar(No **pRaiz,int n){
//Se o nó tem o número retorna ele
if((*pRaiz)->num == n) return (*pRaiz);
//Se o número desse nó é maior que 'n', procura 'n' a esquerda
if((*pRaiz)->num > n) return buscar(&(*pRaiz)->L,n);
//Caso contrário procura 'n' a direita
else return buscar(&(*pRaiz)->R,n);
}
/*Retorna o pai do nó que possui o número 'n' salvo*/
No* buscarPai(No **pRaiz,int n){
No* pai = NULL;
//Se o nó atual possir o número retorna ele (caso o número procurado seja a raiz principal da arvore)
if((*pRaiz)->num == n) return (*pRaiz);
//Verifica se existe filho à direita
if((*pRaiz)->R){
//Verifica se o filho a direita possui o número, se sim retorna este nó
if((*pRaiz)->R->num == n) return (*pRaiz);
//Senão passa para o filho à direita
else pai = buscarPai(&(*pRaiz)->R,n);
}
//Verifica se existe filho à esquerda e o pai ainda não foi encontrado
if((*pRaiz)->L && !pai){
//Verifica se o filho a esquerda possui o número, se sim retorna este nó
if((*pRaiz)->L->num == n) return (*pRaiz);
//Senão passa para o filho à esquerda
else pai = buscarPai(&(*pRaiz)->L,n);
}
return pai;
}
/*Insere novo valor na àrvore*/
void inserir(No **pRaiz,int n){
//Caso o nó não exista aloca espaço, insere o número e define filhos como NULL
if(*pRaiz == NULL){
*pRaiz = (No*) malloc(sizeof(No));
(*pRaiz)->R = NULL;
(*pRaiz)->L = NULL;
(*pRaiz)->num = n;
}else{
//Caso o número seja maior que o número do nó insere à direita
if(n > (*pRaiz)->num)
inserir(&(*pRaiz)->R,n);
//Senão insere à esquerda
if(n < (*pRaiz)->num)
inserir(&(*pRaiz)->L,n);
}
}
/*Retonar o menor valor da árvore*/
No* min(No **pRaiz){
//Anda até o ultimo nó à esquerda e o retorna
if((*pRaiz)->L) min(&(*pRaiz)->L);
return (*pRaiz);
}
/*Retonar o maior valor da árvore*/
No* max(No **pRaiz){
//Anda até o ultimo nó à direita e o retorna
if((*pRaiz)->R) max(&(*pRaiz)->R);
return (*pRaiz);
}
/*Remove um número da àrvore (esta função não funciona caso o nó a ser removido tenha NETOS)
REMOVENTO UM NÓ
Casos:
1) Nó não tem filhos: Apenas remove o nó defininindo NULL para sua conexão com o pai
20 20
\ \
21 (X)
2) Nó tem 1 filho: Faz com que o pai do nó aponte para o filho do nó e apaga o nó
20 20 20
\ \ \
21 \ 21 \ (X)
\ \ \
22 22 22
3) 2 filhos: Substitui o nó pelo seu neto à esquerda do deu filho a direita, caso não tenha neto, substitui
pelo filho a direita.
x22x (23) (23)
/ \ / \ / \
19 24 19 24 19 24
/ \ / \ / \
(23) 25 x22x 25 X 25
*/
No* remover(No **pRaiz,int n){
//Caso não encontre número, exibe mensagem de erro
if (*pRaiz == NULL) {
printf("\n%d não existe nesta àrvore!\n",n);
return *pRaiz;
}
//Procura e remove nó com o número a ser excluído
if (n < (*pRaiz)->num){
(*pRaiz)->L = remover(&(*pRaiz)->L, n);
}
else if(n > (*pRaiz)->num){
(*pRaiz)->R = remover(&(*pRaiz)->R, n);
}
//Quando encontra
else {
//Apenas 1 filho à direita
if ((*pRaiz)->L == NULL) {
No *temp = (*pRaiz)->R;
free(*pRaiz);
return temp;
}
//Apenas 1 filho à esquerda
else if ((*pRaiz)->R == NULL) {
No *temp = (*pRaiz)->L;
free(*pRaiz);
return temp;
}
//2 filhos
No *temp = min(&(*pRaiz)->R); //Obtem nó com o menor número
(*pRaiz)->num = temp->num; //Troca valores com o menor número
(*pRaiz)->R = remover(&(*pRaiz)->R, temp->num); //Chama a remoção para a ultimo nó
}
return *pRaiz;
}
/*Retorna a altura de um nó*/
int altura(No **pRaiz) {
//Se não existe a altura é -1
if ((*pRaiz) == NULL) return -1;
else {
//Obtem as alturas da esquerda e direita
int hl = altura(&(*pRaiz)->L);
int hr = altura(&(*pRaiz)->R);
//Retorna a hr+1 se a altura direita for maior, caso contrário retorna hl+1
if (hl < hr)
return hr + 1;
else
return hl + 1;
}
}
/*Calcula o fator de balanceamento da alvore*/
void getFb(No **pRaiz) {
/*(fb) = hr - hl*/
if (*pRaiz != NULL) {
(*pRaiz)->fb = altura(&(*pRaiz)->R) - altura(&(*pRaiz)->L);
getFb(&(*pRaiz)->L); //Calcula fb da esquerda
getFb(&(*pRaiz)->R); //Calcula fb da direita
}
}
/*Rotação à direita*/
No* rotR(No** pRaiz){
No* q,*temp;
q = (*pRaiz)->L;
temp = q->R;
q->R = (*pRaiz);
(*pRaiz)->L = temp;
*pRaiz = q;
return *pRaiz;
}
/*Rotação à esquerda*/
No* rotL(No** pRaiz){
No* q = NULL;
No* temp = NULL;
q = (*pRaiz)->R;
temp = q->L;
q->L = *pRaiz;
(*pRaiz)->R = temp;
*pRaiz = q;
return *pRaiz;
}
/*Rotação esquerda-direita*/
No* rotLR(No** pRaiz){
(*pRaiz)->L = rotL(&(*pRaiz)->L);
return rotR(&(*pRaiz));
}
/*Rotação direita-esquerda*/
No* rotRL(No** pRaiz){
(*pRaiz)->R = rotR(&(*pRaiz)->R);
return rotL(&(*pRaiz));
}
/*Balanceia a àrvore (se fb < -1 ou > 1 está desbalanceada)*/
void balancear(No **pRaiz){
do{
getFb(&(*pRaiz));
if((*pRaiz)->fb < -1){//Caso o nó esteja pesado para a esquerda (-)
//Se o sinal do filho também for negativo rotação simples à direita
if((*pRaiz)->L->fb <= 0)
*pRaiz = rotR(pRaiz);
//Caso contrário rotação esquerda-direita
else
*pRaiz = rotLR(pRaiz);
}else if((*pRaiz)->fb > 1){//Caso nó esteja pesado para a direita (+)
//Se o sinal do filho também for positivo rotação simples à esquerda
if((*pRaiz)->R->fb >= 0)
*pRaiz = rotL(pRaiz);
//Caso contrário rotação direita-esquerda
else
*pRaiz = rotRL(pRaiz);
}
}while((*pRaiz)->fb < -1 || (*pRaiz)->fb > 1); //Fazer isso enquando a raiz não estiver balanceada
}
#define size 6 //número de nós
int main(void) {
No *pRaiz;
criarArvore(&pRaiz);
//Insere nós
int x[size] = {8,4,6,10,2,5};
for(int i = 0; i < size; i++){
inserir(&pRaiz,x[i]);
}
//Mostra estado inicial
printf("Antes:");
showERD(&pRaiz);
printf("\n");
//Remove número 6
remover(&pRaiz,6);
//Balanceia a àrvore
balancear(&pRaiz);
//Mostra estado final da àrvore
printf("\n");
printf("Depois:");
showERD(&pRaiz);
return 0;
}