Olhando os trabalhos que realizei na faculdade. Encontrei uma AVL desenvolvida para a cadeira de estutura de dados. Implementei utilizando como interface gráfica NCURSES, para mostrar a árvore.
Irei compartilhar o código. Com certeza será bastante util para quem está estudando.
Este código tem alguns conceitos interessantes como:
- Não utiliza variáveis globais
- Os dados são inseridos na árvore quando ficar desbalanceada é informado e solicitado ao usuário se deseja balancear a árvore
- Informe como a árvore esta desbalanceada em quatro casos: EE,ED,DD e DE
- Calcula a altura da árvore
- Menu em Ncurses
- Visualização da árvore com Ncurses
/*
* Nome: Marlon Luis Petry
* Description: AVL
compilacao
gcc "Avl-Marlon.c" -o "Avl-Marlon" -g -lncurses -w
Data: 20/10/2005
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
#include
#include
#include
#define CENTERX COLS/2
#define CENTERY LINES/2
#define DIST 5
typedef char string[50];
typedef struct t {
string info;
int alt;
struct t *pai;
struct t *left;
struct t *right;
}tree;
int tipoBal = -1;
string bal[4] = {”Caso EE”,”Caso ED”,”Caso DD”,”Caso DE”};
tree *bal_esq(tree *aux);
tree *bal_dir(tree *aux);
tree *rotacaoRR(tree *aux);
tree *rotacaoLL(tree *aux);
tree *rotacaoLR(tree *aux);
tree *rotacaoRL(tree *aux);
tree *insere(tree **root, string info, int h) {
char ch;
tree *aux;
if (*root == NULL)
{
aux = (tree *) malloc(sizeof(tree));
strcpy(aux->info,info);
aux->left = NULL;
aux->right = NULL;
aux->pai = NULL;
aux->alt = 0;
h = 1;
*root = aux;
}
else
{
if (strcmp(info,(*root)->info) < 0)
{
insere(&(*root)->left, info, h);
//Atualiza PAI do nó inserido
if ((*root)->left->pai == NULL)
(*root)->left->pai = *root;
if (h)
switch((*root)->alt)
{
//Estava mais alto à direita e inseriur mais um nó à esquerda
case -1:
(*root)->alt = 0;
h = 0; //Não propaga os ajustes nos fatores de balanceamento
break;
case 0:
(*root)->alt = 1; //o lado esquerdo fica maior e os fatores de
//balanceamento acima deverao ser ajustados
break;
case 1:
mvprintw(8,10,”Arvore Desbalaceou a esquerda A = %s Y = %s”,(*root)->info,info);
mvprintw(9,10,”Baleancear (S)im (N)nao: “);
scanw(”%c”,&ch);
if(ch == ‘S’ || ch == ’s’)
{
*root = bal_esq(*root); //FB == 2 -> retorna a sub-árvore balanceada
h = 0; //não propaga a atualização dos fatores de
} //balanceamento
break;
}
}
else
{
insere(&(*root)->right, info, h);
//Atualiza PAI do nó inserido
if ((*root)->right->pai != NULL)
(*root)->right->pai = *root;
if (h)
switch ((*root)->alt)
{
//estava mais alto à esquerda e inseriu mais um nó à direita
case 1:
(*root)->alt = 0;
h = 0; //não propaga os ajustes nos fatores de balanceamneto
break;
case 0:
(*root)->alt = -1; // o lado direito fica maior do que o esquerdo e
// o ajuste deve ser propagado
break;
case -1:
//FB == -2 -> retorna a sub-árvore balanceada
mvprintw(8,10,”Arvore Desbalaceou a direita A = %s Y = %s”,(*root)->info,info);
refresh();
mvprintw(9,10,”Baleancear (S)im (N)nao: “);
scanw(”%c”,&ch);
if(ch == ‘S’ || ch == ’s’)
{
*root = bal_dir(*root);
h = 0; //não propaga a atualização dos fatores de
} //balanceamento
break;
}
}
}
return(*root);
}
tree *bal_esq(tree *aux)
{
tree *p;
p = aux->left;
if (p->alt == 1)
{ //sinais iguais e positivo
tipoBal = 1;
aux = rotacaoLL(aux);
}
else
{
tipoBal = 2;
aux = rotacaoLR(aux); //sinais diferentes
}
aux->alt = 0;
return(aux);
}
/*
* O novo nó foi inserido à direita. Ocorreu desbalanceamento (fb == 2)
*/
tree *bal_dir(tree *aux)
{
tree *p;
p = aux->right;
if (p->alt == -1) //Sinais iguais e negativo
{
tipoBal = 3;
aux = rotacaoRR(aux);
}
else
{
tipoBal = 4;
aux = rotacaoRL(aux); //Sinais diferentes
}
aux->alt = 0;
refresh();
return(aux);
}
//rotacoes
tree *rotacaoRR(tree *aux) {
tree *p;
p = aux->right;
aux->right = p->left;
if (p->left != NULL)
p->left->pai = aux;
p->left = aux;
p->pai = aux->pai;
aux->pai = p;
aux->alt = 0;
return(p);
}
tree *rotacaoLL(tree *aux) {
tree *p;
p = aux->left;
aux->left = p->right;
if (p->right != NULL)
p->right->pai = aux;
p->right = aux;
p->pai = aux->pai;
aux->pai = p;
aux->alt = 0;
return(p);
}
tree *rotacaoLR(tree *aux) {
tree *pai; //ponteiro para depois atualizar o pai após a rotação
tree *no_left; //ponteiro para o filho esquerdo para atualizar o FB após a rotação
tree *novo_no; //ponteiro à ser retornado
int FB_fright; //fator de balanceamento do no à direita do filho esquerdo
pai = aux->pai;
no_left = aux->left;
FB_fright = no_left->right->alt;
aux->left = rotacaoRR(no_left);
novo_no = rotacaoLL(aux);
novo_no->pai = pai;
aux->alt = (FB_fright == 1)?-1:0; //Atualiza FB do nó rotacionado
no_left->alt = (FB_fright == -1)?1:0; // Atualiza FB do nó à esquerda do nó rotacionado
return(novo_no);
}
/*
* Atualização do FB e balanceamento para a raÃz esquerda
*/
tree *balanceamento_esquerdo(tree *no, int h) {
tree *f_dir;
int fb_dir;
switch (no->alt) {
case 1:
no->alt = 0;
break;
case 0:
no->alt = -1;
h = 1;
break;
case -1:
f_dir = no->right;
fb_dir = f_dir->alt;
if (fb_dir <= 0) {
f_dir = rotacaoRR(no);
if (fb_dir == 0) {
no->alt = -1;
f_dir->alt = 1;
h = 0;
}
else {
no->alt = 0;
f_dir->alt = 0;
}
no = f_dir;
}
else {
no = rotacaoRL(no);
no->alt = 0;
}
}
return(no);
}
/*
* Atualização do FB e balanceamento para a raiz direita
*/
tree *balanceamento_direito(tree *no, int h) {
tree *f_esq;
int alt_esq;
switch (no->alt) {
case -1:
no->alt = 0;
break;
case 0:
no->alt = 1;
h = 0;
break;
case 1:
f_esq = no->left;
alt_esq = f_esq->alt;
if (alt_esq >= 0) {
f_esq = rotacaoLL(no);
if (alt_esq == 0) {
no->alt = 1;
f_esq->alt = -1;
h = 0;
}
else {
no->alt = 0;
f_esq->alt = 0;
}
no = f_esq;
}
else {
no = rotacaoLR(no);
no->alt = 0;
}
}
return(no);
}
/*
* Busca nó substituto e realizada a remoção (busca o mais à direita do nó esquerdo
*/
tree *busca_remove(tree *no, tree *no_chave, int h) {
tree *no_removido;
if (no->right != NULL) {
no->right = busca_remove(no->right, no_chave, h);
if (h)
no = balanceamento_direito(no, h);
}
else {
strcpy(no_chave->info,no->info);
no_removido = no;
no = no->left;
if (no != NULL)
no->pai = no_removido->pai;
h = 1; //Deve propagar a atualização dos FB
free(no_removido);
}
return(no);
}
/*
* Remoção da Ãrvore AVL
*/
tree *removeTree(tree **raiz, int info, int h) {
if (*raiz == NULL) {
printf(”Chave não localizada !”);
h = 0;
}
else {
if (strcmp((*raiz)->info, info) > 0)
{
removeTree(&(*raiz)->left, info, h);
if (h)
*raiz = balanceamento_esquerdo(*raiz, h);
}
else if (strcmp((*raiz)->info , info) < 0)
{
removeTree(&(*raiz)->right, info, h);
if (h)
*raiz = balanceamento_direito(*raiz,h);
}
else { //Encontrou o elemento a ser removido
if ((*raiz)->right == NULL) {
if ((*raiz)->left != NULL) //Escolhe o nó à esquerda como substituto
(*raiz)->left->pai = (*raiz)->pai;
*raiz = (*raiz)->left;
h = 1;
}
else
if ((*raiz)->left == NULL) {
if ((*raiz)->right != NULL) //Escolhe o nó à direita como substituto
(*raiz)->right->pai = (*raiz)->pai;
*raiz = (*raiz)->right;
h = 1;
}
else { // Busca o elemento mais à direita do nó esquerdo
(*raiz)->left = busca_remove((*raiz)->left, *raiz, h);
//Se necessário efetua balanceamento (Esquerdo pois a função
//busca_remove foi para o nó esquerdo)
if (h)
*raiz = balanceamento_esquerdo(*raiz, h);
}
}
}
return(raiz);
}
tree *rotacaoRL(tree *aux) {
tree *pai; //ponteiro para depois atualizar o pai após a rotação
tree *no_right; //ponteiro para o filho direito para atualizar o FB após a rotação
tree *novo_no; //ponteiro à ser retornado
int FB_fleft; //fator de balanceamento do no à esquerda do filho direito
pai = aux->pai;
no_right = aux->right;
FB_fleft = no_right->left->alt;
aux->right = rotacaoLL(no_right);
novo_no = rotacaoRR(aux);
novo_no->pai = pai;
aux->alt = (FB_fleft == -1)?1:0; //Atualiza FB do nó rotacionado
no_right->alt = (FB_fleft == 1)?-1:0; // Atualiza FB do nó à direita do nó rotacionado
return(novo_no);
}
int maxDepth(tree *node) {
if (node==NULL) {
return(0);
}
else {
int lDepth = maxDepth(node->left);
int rDepth = maxDepth(node->right);
if (lDepth > rDepth) return(lDepth+1);
else return(rDepth+1);
}
}
//print
int print(tree *r,int x, int y)
{
int TotalWidth = width(r)*DIST;
int centerWidth = (x + TotalWidth/2);
int tamStr;
int d = 0;
//int centerWidthLinen= centerWidth +20;
char t;
if(r != NULL)
{
int leftWidth = width(r->left) * DIST;
int rigtWidth = width(r->right) * DIST;
tamStr = strlen(r->info);
mvprintw(y + (DIST/20),(centerWidth -1- (tamStr/2)),”%s”, r->info);
if (r->left != NULL)
{
int leftX = print(r->left, x , y + DIST);
}
if (r->right != NULL)
{
int rightX = print(r->right, x + leftWidth, y + DIST);
}
}
return centerWidth;
}
int width(tree *root)
{
if(root == NULL)
return 1;
else if(root->left == NULL && root->right == NULL)
return 1;
else
return width(root->left) + width(root->right);
}
main()
{
tree *root = NULL;
char ch;
string msg;
string info;
int opt;
int d=0;
initscr();
bkgd(COLOR_PAIR(4));
strcpy(msg,”Pressione Qualquer Tecla”);
while(1)
{
clear();
mvprintw(1,10,”%s”,”(1) - Inserir novo valor “);
mvprintw(2,10,”%s”,”(2) - Mostrar”);
mvprintw(3,10,”%s”,”(3) - Remove”);
mvprintw(4,10,”%s”,”(4) - Altura”);
mvprintw(5,10,”%s”,”(5) - Sair”);
mvprintw(6,10,”[ ]“);
move(6,11);
scanw(”%d”,&opt);
refresh();
switch(opt)
{
mvprintw(10,10,”%d”,opt);
case 1:
mvprintw(7,10,”%s”,”Informe Valor: “);
refresh();
getstr(info);
insere(&root,info,1);
break;
case 2:
clear();
print(root,CENTERX,0);
mvprintw(LINES -2,CENTERX,”%s”,bal[tipoBal]);
tipoBal = -1;
mvprintw(LINES -1,CENTERX,”%s”,msg);
getch();
break;
case 3:
mvprintw(7,10,”%s”,”Informe Valor: “);
refresh();
getstr(info);
removeTree(&root,info,1);
break;
case 4:
//mvprintw(LINES - 1,CENTERX,”%s”,”f para sair “);
mvprintw(7,10,”%s”,”Nivel”);
refresh();
d = maxDepth(root);
mvprintw(8,10,”%d”,d);
refresh();
break;
case 5:
//mvprintw(LINES - 1,CENTERX,”%s”,”f para sair “);
ch = ‘f’;
break;
}
refresh();
if(ch == ‘f’)
break;
}
endwin();
}
Não se esqueça este código é GPL pode ser usado desde que mantido os direitos autorais.
Assinem os FEEDS é de graça. Só essa semana 