terça-feira, 30 de abril de 2013


2º Projeto de Algoritmo e Estrutura de Dados 

1. Objetivos

O objetivo do projeto consiste no desenvolvimento de um programa em linguagem C para criar um dicionário utilizando árvore AVL.

2. Requisitos

O programa deve:
 Possuir um menu para seleção das operações que podem ser realizadas;
 Listar, em ordem crescente, as palavras do dicionário;
 Listar, em ordem crescente, as palavras que começam com uma determinada letra;
 Permitir inserir, pesquisar, alterar e excluir palavras;
 Utilizar funções, árvore AVL e uma lista dinâmica linear;
 O programa deverá ser totalmente desenvolvido pelo aluno, não sendo permitida a utilização de funções e bibliotecas já prontas;
 Em caso de dupla, as notas poderão ser diferenciadas caso seja percebida a participação maior de algum deles. Os alunos poderão ser chamados para a defesa do trabalho, a qualquer momento, caso a professora assim desejar.

3. Dicionário
O dicionário será organizado dentro de uma árvore AVL, onde cada nó será composto pelos seguintes campos:
1) um campo para armazenar uma letra do alfabeto, sobre a qual serão realizadas as pesquisas, inserções, alterações, listagens e remoções de palavras;
2) um campo para armazenar as palavras/descrição em uma lista. Desse modo, cada nó também deverá ter uma lista encadeada, a qual deve permitir inserir, listar, alterar, remover e pesquisar as palavras que iniciem com a letra correspondente a esse nó da árvore;
3) dois campos para armazenar referência ao filho da direita e da esquerda.



Programa

/* 2ª Projeto de Estrutura de dados 
Autoras: Stanelle Silveira , Ayres Rodrigues
Matriculas:2551 , 2510 */

//Bibliotecas necessárias 
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
//#include <conio.h>
//Inicio do programa
/*****************************************************************************************************************/
//ESTRUTURA NECESSARIA
typedef struct lista_de_palavra{                    /*Estrutura tipo lista dinâmica duplamente encadeada*/
   char palavra[15],descri[500];                    /*Declaração das string*/
   struct lista_de_palavra *prox, *ant;             /*Ponteiro de prox que vai guarda o proximo da lista e o ant, vai guarda o endereço do anterior */ 
   }lista;                                     

typedef struct arvore_dado{                         /*Estrutura da arvore*/
   lista *lista_palavra;                            /*Declaração da lista onde será amazenar as palavras e descrições*/
   int bal;                                         /*Varíavel tipo inteiro para auxílio  do balanceamento*/
   char letra;                                      /*Varíavel  */
   struct arvore_dado *esq, *dir;                   /*Ponteiros para ligação das folhas e subarvore da arvore letra*/
   }arvore;
/*****************************************************************************************************************/
//INICIALIZAÇÃO E FUNÇÃO PARA VERIFICAÇÃO ESTÁ VAZIA
arvore *inicializa(arvore *ABC){
   ABC = NULL;
   return ABC;                                     //inicializar  arvore 
}

bool estaVazia(arvore *ABC){
   return (ABC == NULL);                           //Verifica se está vazia  a arvore 
}
/*****************************************************************************************************************/
//PROTÓTIPO DAS FUNÇÕES NECESSARIAS 
void Menu_principal(arvore *ABC);                    //Função do menu principal
void Menu_listar(arvore *ABC);                       //Função da menu lista
void Menu_Manter(arvore *ABC);                       //função do menu manter o dicionari 
void imprimir_por_letra(arvore *R);                  //Função onde vai imprimir a palavra por letra
int avl_insere(arvore **R, char letra1);             //Função inserir arvore ordenado e balaceando
void avl_aux2(arvore **R);                           //Função que auxilia a inseção 
void avl_aux1(arvore **R);                           //Função que auxilia a inseção 
void avl_esqdir(arvore **R);                         //Função de rotação da arvore  de esquerda para direta 
void avl_rotesq(arvore **R);                         // Função de rotação da arvore para o lado  equerda
void avl_rotdir(arvore **R);                         //Função de rotação da arvore para o lado direito
/*****************************************************************************************************************/
//FUNÇÃO PARA AUXILIO DAS ROTAÇÕES 
void avl_rotdir(arvore **R){                         //Função do tipo void, usando ponteiro para ponteiro para que possa fazer seguinte alterações :
   arvore *aux;                                     //Declaração de um ponteiro auxiliar 
                                                 
   aux=(*R)->esq;                                   //O auxiliar vai receber o endereço do lado esquerdo 
   (*R)->esq=aux->dir;                              //A letra que estar no nó R o seu lado esquerdo irá apontar para o que está no lado direito do aux                            
   aux->dir = *R;                                   //A letra que aux recebeu, o seu lado direito irá apontar  para a variável do R                              
   (*R)->bal=0;                                     // o fator de controle do  balanceamento  recebe 0   
   *R =aux;                                         // R vai aponta para o aux fazendo assim modificação na lista 

}
/*****************************************************************************************************************/
//ROTAÇÃO PARA A ESQUERDA
void avl_rotesq(arvore **R){                        //Função do tipo void, usando ponteiro para ponteiro para que possa fazer seguinte alterações :
   arvore *aux;                                     //Declaração de um ponteiro auxiliar     
   
   aux=(*R)->dir;                                   //O auxiliar vai receber o endereço do lado direito de R 
  (*R)->dir=aux->esq;                               //A letra que estar no nó R o seu lado direito irá apontar para o que está no lado esquerdo do aux
  aux->esq = *R;                                    //A letra que aux recebeu, o seu lado esquerdo irá apontar  para a variável do R 
  (*R)->bal=0;                                      // bal (variavel do balanceamento) recebe 0 
  *R =aux;                                          // R passa a ser aux

}
/*****************************************************************************************************************/
//ROTAÇÃO DUPLA PARA A DIREITA - REALIZANDO PRIMEIRO A ESQUERDA E DEPOIS A DIREITA 
void avl_esqdir(arvore **R){
     arvore *fe, *ffd;                            //declaração de dois ponteiro do tipo arvore  
                                                
   fe=(*R)->esq;                                //fe recebe o endereço a esquerda de R, para realizar tal movimentação, já que não podemos modificar os ponteiros ainda
   ffd=fe->dir;                                 //ffd recebe o endereço a direita de fe que e a esquerda de R
                                                //Rotação a esquerda 
   fe->dir=ffd->esq;                            //a direita de fe recebe o endereço da esquerda de ffd ou seja o menor elemento de ffd vai ser apontado pelo fe
   ffd->esq=fe;                                 //a esquerda de ffd recebe fe
                                                //Rotação a direita 
   (*R)->esq=ffd->dir;                          //a esquerda de R recebe o endereço da direita de ffd
   ffd->dir=*R;                                 //a direita de ffd recebe R, assim a arvore vai estar balaceada 

   if(ffd->bal==+1)                             //se o fator de balanceamento de ffd for +1
      (*R)->bal=-1;                             // o fator de balanceamento de R passará a ser -1
   else 
      (*R)->bal=0;                              //senão passará a ser 0
   if(ffd->bal==-1)                             //se o fator de balanceamento de ffd for igual a -1 
      fe->bal=1;                                //o fator de balanceamento de fe passará a ser 1 
   else
      fe->bal=0;                                //senão a passará a ser o
   *R=ffd;                                      //R receberá ffd fazendo então as modificação na arvore
}
     
/*****************************************************************************************************************/
//ROTAÇÃO DUPLA PARA A ESQUERDA - FAZENDO A DIREITA SOBRE O FILHO E A ESQUERDA
void avl_diresq(arvore **R){
   arvore *fe, *ffd;                         //declaração de ponteiros do tipo arvore para auxilio
   fe= (*R)->dir;                            //fe recebe o endereço a direita de R, para realizar tal movimentação, já que não podemos modificar os ponteiros ainda
   ffd=fe->esq;                              //ffd recebe o endereço a esquerda de fe que e a direita de R
                                             //Rotação a direita
   fe->esq=ffd->dir;                         //a esquerda de fe receberá o endereço a direita de ffd
   ffd->dir=fe;                              //a direita de ffd receberá o endereço de fe 
                                             //Rotação a esquerda
   (*R)->dir=ffd->esq;                       //a direita de R receberá o endereço a esquerda de ffd
   ffd->esq=*R;                              //a esquerda de ffd receberá R, assim a arvore vai estar balaceada

   if(ffd->bal==+1)                          // se o fator de balanceamento de ffd for igual a +1
      (*R)->bal=-1;                          // o fator de balanceamento de R passará a ser -1
   else 
      (*R)->bal=0;                           //senão passará a ser 0
   if(ffd->bal==-1)                          //se o fator de balanceamento de ffd for -1 
      fe->bal=1;                             // o fator de balanceamento de fe passaá a ser 1
   else                                      //senão 
      fe->bal=0;                             //passará a ser 0
   *R=ffd;                                   //R receberá ffd fazendo então as modificação na arvore
}
/*****************************************************************************************************************/
//AUXILIAR DE ROTAÇÃO
void avl_aux1(arvore **R){
   arvore *fe;             //declaração de ponteiro do tipo arvore
   fe =(*R)->esq;          // fe recebe o endereço esquerda de R
   if(fe->bal==+1)         // se o fator de balanceamento for +1
      avl_rotdir(&(*R));   // é chamado a rotação a direita 
   else                    //senão 
      avl_esqdir(&(*R));   //é chamado a rotação esquerda/direita(Dupla a direita)
   (*R)->bal=0;            //o fator de balanceamento recebe 0
}
/*****************************************************************************************************************/
//AUXILIAR DE ROTAÇÃO
void avl_aux2(arvore**R){
   arvore *fd;         //declaração de ponteiro do tipo arvore

   fd=(*R)->dir;        //fd recebe a direita de R
   if(fd->bal==-1)      //se o ofator de balanceamento desse nó for -1 
   avl_rotesq(&(*R));   //é chamado a rotação a esquerda 
   else                 //senão 
      avl_diresq(&(*R));// é chamado a direita/esquerda(Dupla a esquerda )
   (*R)->bal=0;         //fator de balanceamento recebe 0
}
/*****************************************************************************************************************/
//FUNÇÃO PARA INSERÇÃO DOS NÓS NA ARVORE BALANCEANDO
int  avl_insere(arvore **R, char letra1){           //Função tipo inteiro, com parâmetro ponteiro para ponteiro e a letra de inserção 
   int certo;                                       //Declaração da Variável auxiliar 
                                                    
   if(*R==NULL){                                    //Só vai entrar nesse nó em dois casos:1-arvore vazia , 2- só depois que retornar a recursiva assim encontrando o local onde será inserido.
      *R = (arvore*) malloc (sizeof(arvore));       //Alocação de memoria para para o nó R
      if(*R==NULL)                                  //caso nao seja possivel aloca retorna 0;
         return 0;                                  //Retorno zero 
      (*R)->lista_palavra=NULL;                     //Inicializa a lista de palavra com NULL
      (*R)->esq=NULL;                               //O lado esquerdo recebe NULL
      (*R)->dir=NULL;                               //O lado direito recebe NULL
      (*R)->letra=letra1;                           //O nó recebe a letra que o usuário deseja inserir
      (*R)->bal=0;                                  //Atualiza o fator de balanceamento
      return 1;                                     //retorna 1 
   }

   if(letra1< (*R)->letra){                        //Nessa função de condição é verificado se a letra é menor que a letra que estar localizada na arvore
      certo= avl_insere(&((*R)->esq),letra1);      //Chama a funça de inserir  novamente, passando como parâmetro o lado esquerdo para verificação e aguardar o retorno 1 para o fazer as modificações abaixo : 
      if(certo){                                   //Se a variável for igual a 0 entra nessa condição 
         switch ((*R)->bal){                       //função de condição para verificação do fator
            case -1:                               //caso seja -1 entra no case
               (*R)->bal=0;                        //Atualiza o fator de balanceamento
               certo=0;                            // Certo recebe 0, retornando para chamada recursiva
               break;                 
            case 0:                                //Caso seja 0 entra no case
               (*R)->bal=+1;                       //Atualiza o fator de balanceamento
               break;
            case +1:                               //caso seja 1 entra no case
               avl_aux1(&(*R));                    //Chamada da função auxiliar 1, irá acontecer a rotação:  direita ou a dupla, esquerda e direita
               certo=0;                            // Certo recebe 0, retornando para chamada recursiva
               break;
          }
      }
   }
   else                                            //Caso a letra for maior ou igual a letra armazanada na arvore, entra nessa condição 
      if(letra1 >(*R)-> letra){                    //Entra nessa função se a letra for maior que a letra da arvore 
         certo=avl_insere(&((*R)->dir),letra1);    //Chama a funça de inserir  novamente, passando como parâmetro o lado direito para verificação e aguardar o retorno 1 para o fazer as modificações abaixo : 
         if(certo){                                //caso a variavel certo seja igual a 0, entra nessa condição
            switch ((*R)->bal){                    //função de condição para verificação do fator
               case +1:                            //caso seja 1 entra no case         
                  (*R)->bal=0;                     //Atualiza o fator de balanceamento
                  certo =0;                        // Certo recebe 0, retornando para chamada recursiva 
                  break;
               case 0:                             //Caso seja 0 entra nesse case
                 (*R)->bal= -1;                    //Atualiza o fator de balanceamento
                  break;
               case -1 :                          //Caso seja -1 entra nesse case
                  avl_aux2(&(*R));                //Chamada da função auxiliar 2, irá acontecer a rotação:  esquerda ou a dupla, direita e esquerda 
                  certo =0;                       // Certo recebe 0, retornando para chamada recursiva
                  break;
            }
         }
      }
       else {                                    //Caso a letra seja igual entra nessa função 
         certo =0;                               // Certo recebe 0, retornando para chamada recursiva
       }
   return certo;
}
/*****************************************************************************************************************/
//FUNÇÃO PARA ENCONTRAR O MAIOR NÓ A DIREITA 
arvore *maximo(arvore *R){
   if(estaVazia(R))                            //Se a arvore estiver vazia 
      return NULL;                             //retorna NULL
   else                                        //senão
      if( estaVazia(R->dir) )                  //chamo estaVazia novamente passando a direita de R
         return R;                             //se estiver vazia retorno R 
      else                                     //senão estiver vazia 
         return maximo(R->dir);                //chamo a função máximo novamente passando a direita de R
}
/*****************************************************************************************************************/
//FUNÇÃO PARA ATUALIZAR OS FATORES DE BALANCEAMENTO DEPOIS DA EXCLUSÃO
int Altura_atualiza(arvore *R) {
   if (R == NULL)                             //Ponto de parada da recursão
      return 0;
   int hesq =Altura_atualiza(R->esq);        //hesq receberá altura da sub arvore a esquerda
   int hdir = Altura_atualiza(R->dir);       //hdir receberá a altura da sub arvore a direita 
   R->bal = hesq - hdir;                     //bal receberá a diminuição da altura a esquerda pela a direita 
  
   if(hesq > hdir)                           //se a sub arvore a esquerda for maior q a direita
      return hesq + 1;                       //retornará a altura + 1 para o lado esquerdo
   else                                      //se o lado direito for  menor entra nesse else
      return hdir + 1;                       //retornará a altura direita + 1 para o lado direito
}
/*****************************************************************************************************************/
//VERIFICA SE A ÁRVORE ESTÁ BALANCEADA APOS A EXCLUSÃO,CASO NÃO ESTEJA CHAMA A ROTAÇÃO NECESSÁRIA
void verifica(arvore **R){  //função que trabalha junto a função Altura_atualiza
   int aux;                           //Declaração de aux
   aux = Altura_atualiza(*R);         //aux receberá o retorno da função Altura_atualiza
   
   if(aux >2 && ((*R)->esq != NULL || (*R)->dir != NULL)){//caso aux for menor que dois não precisa entrar na função
                                                               //pois mesmo apos a exclusão continua balanceada 
      if(*R == NULL)                                   //ponto de parada 
         verifica(&((*R)->esq));                          //passo a esquerda 
      if((*R)->bal < 0 && ((*R)->dir->bal == 0 || (*R)->dir->bal == -1 )){//se o bal for negativo e o filho a direita 
         avl_rotesq(&(*R));                                            // for 0 ou -1 
                                                                                   //será uma rotação simples a esquerda
      }else if((*R)->bal>0 &&((*R)->esq->bal == 0 || (*R)->esq->bal == 1)){ //se bal for positivo e o filho a esquerda
         avl_rotdir(&(*R));                                         //for 0 ou 1
                                                                                    //rotação simples a direita
      }else if( (*R)->bal < 0 && (*R)->dir->bal == 1){//se o bal for negativo e o filho a direita 
         avl_diresq(&(*R));                     // for 1 rotação dupla a esquerda
      }else if((*R)->bal >0 && (*R)->esq->bal == -1){ //se bal for positivo e o filho a esquerda
         avl_esqdir(&(*R));                           //for -1 rotação dupla a direita
      }
         verifica(&((*R)->dir));                                     //passo a direita 
   }
}
/*****************************************************************************************************************/
//FUNÇÃO PARA REMOÇÃO DOS NÓS DA ARVORE
arvore *remover(arvore *R, char letra){        //Função remover do tipo arvore
   arvore *aux;                                //ponteiro auxiliar do tipo arvore

   if(R!=NULL)                                 //So vai entrar nessa função caso R seja diferente de NULL
      if(letra < R->letra)                     //Caso a letra seja menor que a letra existente na arvore entra nesse if
         R->esq = remover(R->esq, letra);      //irá percorre toda subarvore a esquerda, para achar a letra que o usuário deseja excluir
      else                                     //A letra e maior ou igual a letra existente na arvore
         if(letra>R->letra)                    //se a letra que vai ser removida for maior que a que está na arvore
            R->dir = remover(R->dir,letra);    //irá percorre toda subarvore a direito, para achar a letra que o usuário deseja excluir
         else {                                //caso não satisfaz nenhum dos caso feito anteriormente quer dizer que achou a letra 
            if(!estaVazia(R->esq) && !estaVazia(R->dir) ){//Verificação se o nó nao tem filhos
               aux = maximo(R->esq);           //aux recebe o endereço do nó maior a esquerda
               R->letra = aux->letra;          //R recebe a letra maior da esquerda          
               R->esq = remover(R->esq, R->letra); //A esquerda de R recebe o retorno da função remover
            }
            else{                               //caso tenha filho ou subarvore entra no else
               aux = R;                         //aux recebe o nó R
               if(estaVazia(R->esq))            //se a esquerda de R está vazia entra nesse if
                  R = R->dir;                   // verificação para o retorno dos nó : R recebe o endereço a direita de R 
               else                             //senão
                  R = R->esq;                   //R recebe o endereço a esquerda de R
           free(aux);                            // libera a memória ocupada por aux
          }
        }
return R;                                       //Retorno do R

/*****************************************************************************************************************/
//FUNÇÃO PARA IMPRIMIR TODAS AS PALAVRAS E SUAS DESCRIÇÕES DO DICIONÁRIO EM ORDEM ALFABÉTICA
void imprimir_completo(arvore *R){

   lista *aux3;                 //ponteiro do tipo lista ,onde estão as palavras
   if(R != NULL){              //se a arvore não estiver vazia
      imprimir_completo(R->esq); //chamo imprimir completo passando a esquerda
      aux3 = R->lista_palavra;   //aux3 recebe o o endereço que o nó R aponta, sendo o primeiro endereço da lista
      printf("\n\n\n");            
      printf("|-----------------------------------------------------------------------|\n"); //tabela
      printf("                     ***         %c       ***                           \n",toupper(aux3->palavra[0])); // imprimi a letra 
      printf("|-----------------------------------------------------------------------|\n"); //tabela
      printf("   PALAVRA            \t|       DESCRICAO                                     \n");//tabela
      printf("|-----------------------------------------------------------------------|\n");
      while (aux3!= NULL){  //entra em um laço de repetição parando quando chegar ao fim da lista de palavras 
         printf(" * %s             \t| %s                                        \n",aux3->palavra,aux3->descri); //imprimi a palavra
         printf("|-----------------------------------------------------------------------|\n");                   // e sua descrição 
         aux3 = aux3->prox; //aux3 recebe o endereço do próximo nó da lista
     }
     imprimir_completo(R->dir); //passo a direita 
   }
}

/*****************************************************************************************************************/
//FUNÇÃO DE INSERIR PALAVRA NA LISTA ORDENADA.
arvore *inserir_palavra(arvore *R, char palav[]){      //função que insere ordenado as palavras na lista da letra começada com a palavra
   lista *aux, *auxI;                                  //ponteiro auxiliares do tipo lista duplamente encadeada                                
   aux =(lista*)malloc(sizeof(lista));                 //alocação da variavel aux
   if(aux == NULL)                                     // se aux for igual a null a alocação nao foi possível
      printf("A alocacao nao foi porssivel");          //caso entre no if o usuario será informado que alocação nao foi possível
   else{                                               //Caso a alocação foi feita com sucesso, entra nesse else
      strupr(palav);                                   //função da biblioteca string.h para transformar minúsculas em maiúsculas
      strcpy(aux->palavra,palav);                      //função da biblioteca string.h para copiar uma string em outra, assim aux recebe a palavra
      fflush(stdin);                                   //limpo o buffer
      scanf("%s",&aux->descri);                               // função gets para pegar a descrição da palavra
      if((R->lista_palavra == NULL)|| (strcmp(aux->palavra,R->lista_palavra->palavra)<0)){//Entra nessa condição em dois momento: 1- nao existe no nenhum na lista 2- a palavra que o usuário deseja inserir e menor que a primeira da lista
         aux->prox = R->lista_palavra;                //o prox do aux recebe o proximo da lista, caso seja o primeiro a ser inserido, aux prox recebe NULL
         aux->ant = NULL;                             // o ant de aux recebe NULL
         if(R->lista_palavra!= NULL)                  //Caso nao seja o primeiro nó entra nesse if
            R->lista_palavra->ant= aux;               //O ponterio que aponta para o primeiro nó da lista, recebe aux 
         R->lista_palavra = aux;                      // o endereço do primeiro nó da lista passa a ser aux
      }else {                                         //caso nao satisfaz as condições acima entra nesse else
         auxI = R->lista_palavra;                    //auxI recebe o endereço do primeiro nó da lista de palavras, para uma pesquisa
         while (auxI->prox != NULL && ( strcmp(aux->palavra,auxI->palavra)>=0))// entra nessa condição se a palavra e maior ou igual a palavra que a auxiliar 2 
            auxI = auxI->prox;                       //Aux1 vai recebe a proxima palavra
        if(strcmp(aux->palavra,auxI->palavra)>=0){   // Inserir no final o novo nó que será o ultimo da lista
           aux->prox = NULL;                         //O prox de aux recebe NULL
           aux->ant = auxI;                          //A posição ant recebe o endereço do ultimo nó
           auxI->prox = aux;                        //O ultimo nó passa apontar para o novo nó
        }else{                                       //se não satisfaz a condição anterior, entra nesse caso que vai inserir no meio
           aux->prox = auxI;                         //O novo nó na posição prox recebe e endereço de aux1
           aux->ant = auxI->ant;                     //O ant do aux recebe o endereço do do ant da auxiliar aux1
           aux->prox->ant = aux;                    //O novo nó na posição prox que aponta para o endereço do próximo na posição ant recebe endereço de aux
           aux->ant->prox = aux;                    //O novo nó na posição ant que aponta para o endereço do anterior na posição prox recebe endereço de aux
        }

      }
   }
   return R;    //retorno R
}

/*****************************************************************************************************************/
//FUNÇÃO PARA PESQUISA NA ARVORE
arvore* pesq_arvore(arvore *R, char dadoPesq){ //recebe R e o dado a ser pesquisado 
   while (R != NULL && R->letra != dadoPesq){  //entra no laço de repetição enquanto R for diferente de NULL e  a letra proxima for diferente da letra procurada
      if (dadoPesq < R->letra)                 // a letra pesquisada e menor que a letra encontrada na arvore
         R = R->esq;                           //caso o dado pesquisado for menor do que a letra que está na arvore, R percorre o lado esquerdo
      else                                     //caso nao satisfaz a condição anterior entra nesse else
         R = R->dir;                           //caso o dado pesquisado for maior do que a letra que está na arvore, R percorre o lado direito
   }
   return R;                                   //retorno o endereço onde o dado localiza
}

/*****************************************************************************************************************/
//FUNÇÃO PARA IMPRIMIR PALAVRAS
lista *imprimir_palavra(arvore *R,char palavra[]){
   char prim_letra; //prim_letra para receber a letra inicial da palavra
   lista *aux;      //ponteiro do tipo lista
   arvore *pesq;    //ponteiro do tipo arvore
   aux=NULL;         //aux inicializado com NULL
   prim_letra=palavra[0]; //prim_letra recebe a inicial da palavra


    if (estaVazia(R)){ //se a lista está vazia 
      printf("\n\nLista VAZIA!\n\n");//informa ao usuário
    }
    else{

         pesq = pesq_arvore(R,prim_letra); //pesq recebe o enderço que será retornado por pes_arvore
         if(pesq == NULL){  // se pesq for NULL é porque não existe a palavra procurada 
             printf("\nPalavra nao existe\n");//informe ao usuário
             aux = NULL; //aux recebe NULL
         }else{
               aux = pesq->lista_palavra;
               while(aux != NULL && strcmp(aux->palavra,palavra) != 0)
                     aux = aux->prox;
               if(aux==NULL)//se aux for igual a NULL
                        printf("\nPalavra nao existe\n"); //mensagem ao usuário
               else { //senão imprimi a palavra e sua descrição
                   printf("\n|--------------------------------|\n"); //tabela 
                   printf("           %s                 \n",aux->palavra);//imprimi a palavra
                   printf("\n|________________________________|\n");
                   printf("           %s                 \n",aux->descri); //imprimi a descrição
                   printf("\n|--------------------------------|\n");

                   }
               }
               }
   return aux; //retorno de aux
}
/*****************************************************************************************************************/
//NESSA FUNÇÃO VAI PESQUISAR SE A PALAVRA EXISTE E SE JÁ TEM UM NÓ NA ARVORE COMERÇADA COM A INICIAL DA PALAVRA
arvore* pesq_inserir(arvore *R){                           //Função tipo arvore
   arvore *pesq;                                          //ponteiro auxiliar para pesquisa tipo arvore
   lista *aux,*auxp;                                      //ponteiros auxiliares do tipo lista 
   char resp,prim_letra,palavra[10];                      //variáveis do tipo char - caracter
   int resb,num;                                          //variáveis do tipo int - inteiro
   
   printf("\n Entre com a palavra por favor:\n");        //mensagem ao usuário
   fflush(stdin);                                        //limpa o buffer 
  scanf("%s",&palavra);                                        //função gets para inserir a palavra
   strupr(palavra);                                     //função para transforma minúscula em maiúscula
   printf("\nDeseja inserir descricao? \n\n S=sim  ou N=nao: _");//mensagem ao usuário

   do{ //laço de repetição
      resp=toupper(getch());//receber a resposta do usuário
   }while(resp !='S' && resp != 'N'); //repete enquanto a resposta do usuário for dirente de S e N

   if(resp=='N'){//se a resposta do usuário for N entra nesse if
      auxp=imprimir_palavra(R,palavra); // Chama a função onde irá informa se a palavra existe e caso existir vai imprimir
   }else{//caso o usuário digite S entra nesse else
      prim_letra=palavra[0];//variavel vai reveber a primeira letr da palavra
      pesq = pesq_arvore(R,prim_letra);//pesquisar se existe o primeirora letra na arvore
      if(pesq==NULL){//caso a pesquisa volte NULL entra nessa função, onde irá criar um nó para ela 
            num=avl_insere(&R,prim_letra);//insere o nó na arvore e logo balacea 
            printf("\nDigite a descricao da palavra %s\n\n",palavra);
            pesq=pesq_arvore(R,prim_letra);//pesquisa novamente o endereeço do nó na arvore, onde está a inicial da palavra
            pesq =inserir_palavra(pesq,palavra);//insere a palavra na lista de palavras 
      }
       else {//caso nao satisfaz as condições anteriores entra nesse else
         if(pesq!=NULL){//Nesse caso já existe o nó da inicial na arvore
            aux= pesq->lista_palavra;//aux vai axiliar na inserção da palavra, ele recebe o primeiro da lista 
            while(aux != NULL && strcmp(aux->palavra,palavra) != 0) //pesquisa da palavras , tem que ser diferente de NULL e diferente da palavra procurada
               aux = aux->prox;//aux vai caminhar até encontrar a palavra igual ou nao existe
            if(aux==NULL){ //se aux for igual a NULL

                  printf("\nDigite a descricao da palavra %s\n\n",palavra);//imprimi mensagem
                  pesq=pesq_arvore(R,prim_letra);//pesquisa novamente o nó da inicial 
                  pesq =inserir_palavra(pesq,palavra);//insere a palavra
               
              }else //caso NULL for diferente de NULL, que dizer que a palavra já existe
                 if(aux!=NULL){ // senão se aux for diferente de NULL
                 
                       printf("\n O dicionario ja possui essa palavra\n");//imprimi a mensagem
                       auxp=imprimir_palavra(R,palavra);//imprimi a palavra e sua descrição  
                    
                 }

         }

      }
   }
   return R;        //retorno arvore
}
/*************************************************************************************/
//FUNÇÃO EXCLUIR PALAVRA
arvore *excluir(arvore *R,char dado[]){
   lista *aux;                        //Um ponteiro auxiliar do tipo lista de palavra
   char resp,letra;                   //variavel resp para as reposta do usuario e letra para receber a primeira letra da palavra
   arvore *pesq;                      // Um ponteiro  tipo arvore para pesquisar a primeira letra na arvore
      system("cls");           
   pesq=NULL;                          //inicializa o ponteiro 
                    
   if (estaVazia(R))                   //verificar se alista está vazia 
      printf("\n\nLista VAZIA!\n\n");  //informar o usuario
   else{                               //caso nao esteja vazia entra nesse condição 
      letra=dado[0];                   //letra vai receber a primeira letra da palavra 
      aux = imprimir_palavra(R,dado);  //minha auxiliar vai receber o retorno do função imprimir palavra, e nessa função irá ser verificado a existencia da palavra
      if(aux!=NULL){                   // caso aux seja diferente de NUll quer dizer que existe a palavra, entra nesse if 
         printf("\n\nDeseja realmente excluir palavra s-sim , N- nao\n\n"); 
         fflush(stdin);
         do{
            resp=toupper(getch());                                //receber a resposta
         }while(resp !='S' && resp != 'N');                       //caso ele digite outro caracter nao pedido, voltar a pedi novamente 
         if (resp=='S'){                                          // se a reposta for sim entra nesse if para que seja feita a exclusão 
            pesq=pesq_arvore(R,letra);                            // pesquisar a existencia da letra na arvore       
            if(aux == pesq->lista_palavra){                       // aux é  o endereço onde estar a palavra a ser excluido, logo se  ela for igual o edereço da primeira palavra do no que pesq quarda o endereço, entra nesse if.
               if (aux->prox != NULL)                             //Existe uma proxima palavra depois daquela que deseja excluir 
                  aux->prox->ant = NULL;                          //O nó da palavra que vem depois da que deseja excluir recebe NULL
               pesq->lista_palavra = pesq->lista_palavra->prox;   // a lista na arvore irá apontar para a proxima palavra    
            }else{                                                //caso nao seja a palvra próxima entra nessa condição 
               if (aux->prox != NULL)                             //Existe uma proxima palavra depois daquela que deseja excluir
                  aux->prox->ant = aux->ant;                      //Vai ligar os nó que estão ao redor do nó excluido 
               aux->ant->prox = aux->prox;                        // O anterior recebe o proximo depois  do que o usuário deseja excluido 
            }
            if(pesq->lista_palavra==NULL){                        //Caso a palavra seja a ultima do nó da arvore entra nesse if
               R=remover(R,letra);                                //remove o nó da inicial da palavra na arvore 
            }
            free(aux);                                            //nó excluido 
           
           
         }
      }
   }         
   system("pause");
   return R;//retorna modificações 
}

/*****************************************************************************************************************/
//FUNÇÃO PARA ALTERAR AS DESCRIÇÕES DAS PALAVRAS
arvore *Alterar(arvore *R){
       char palavra[10],descri[100],op;  //variáveis do tipo char - caracter
       lista *auxp;  
       lista *aux;                        //Um ponteiro auxiliar do tipo lista de palavra
       char resp,letra;                   //variavel resp para as reposta do usuario e letra para receber a primeira letra da palavra
       arvore *pesq;                      // Um ponteiro  tipo arvore para pesquisar a primeira letra na arvore
           int resb;   
      pesq=NULL;                            //inicializa o ponteiro 
                          //ponteiro do tipo arvore 
       printf("\n\nDigite a palavra desejada :   "); //mensagem ao usuário
       fflush(stdin);                              //limpeza do buffer
       scanf("%s",&palavra);                             //função para pegar a palavra digitada
       strupr(palavra);                           // função que transforma minúscula em maiúscula
       if (estaVazia(R))                   //verificar se alista está vazia 
       printf("\n\nLista VAZIA!\n\n");  //informar o usuario
      else{  
          letra=palavra[0];                   //letra vai receber a primeira letra da palavra 
                                 //caso nao esteja vazia entra nesse condição 
           aux = imprimir_palavra(R,palavra); 
           //system("pause>>null");
                  //chamada da função para imprimir a palavra e sua descrição
       if(aux != NULL){                          
               printf("\n\n\nPara alterar a palavra e descricao digite   S\nPara alterar apenas a descricao digite     D\nCaso deseja nao alterar nada dite       N \n\n");//mensagem ao usuário
              do{
                   op = toupper(getch()); 
                 }while(op == 'S'&& op=='D' && op=='N'); //função getchar para pegar aresposta do usuário e ao mesmo tempo transformar em maiúscula
                  if(op=='D'){
                      printf("\nDigite a nova descricao:  "); //mensagem ao usuário
                      fflush(stdin);                           //limpeza do buffer 
                      scanf("%s",&descri);                           //altera a descrição, pegando uma nova 
                      strcpy(aux->descri,descri);            //copia da string descri para a descrição do nó lista
                   } else if(op=='S') {                                        //que está na arvore 
       
                  

      //minha auxiliar vai receber o retorno do função imprimir palavra, e nessa função irá ser verificado a existencia da palavra
      
                                         //receber a resposta
                              //caso ele digite outro caracter nao pedido, voltar a pedi novamente 
                                             // se a reposta for sim entra nesse if para que seja feita a exclusão 
            pesq=pesq_arvore(R,letra);                            // pesquisar a existencia da letra na arvore       
            if(aux == pesq->lista_palavra){                       // aux é  o endereço onde estar a palavra a ser excluido, logo se  ela for igual o edereço da primeira palavra do no que pesq quarda o endereço, entra nesse if.
               if (aux->prox != NULL)                             //Existe uma proxima palavra depois daquela que deseja excluir 
                  aux->prox->ant = NULL;                          //O nó da palavra que vem depois da que deseja excluir recebe NULL
               pesq->lista_palavra = pesq->lista_palavra->prox;   // a lista na arvore irá apontar para a proxima palavra    
            }else{                                                //caso nao seja a palvra próxima entra nessa condição 
               if (aux->prox != NULL)                             //Existe uma proxima palavra depois daquela que deseja excluir
                  aux->prox->ant = aux->ant;                      //Vai ligar os nó que estão ao redor do nó excluido 
               aux->ant->prox = aux->prox;                        // O anterior recebe o proximo depois  do que o usuário deseja excluido 
            }
            if(pesq->lista_palavra==NULL){                        //Caso a palavra seja a ultima do nó da arvore entra nesse if
               R=remover(R,letra); 
                                            //remove o nó da inicial da palavra na arvore 
            }
            free(aux);                                            //nó excluido 
          
            resb = Altura_atualiza(R);//função para Atualizar o fator
           verifica(&R);//verificar se a arvore está balanceada se nao balanceia 
           resb = Altura_atualiza(R);
            R=pesq_inserir(R); 
         }else if(op=='N') 
         printf("Palavra nao alterada\n");
      }
   }         
   system("pause");
   return R;//retorna modificações 
       return R;                                            //retorno R com as modificações
}
/*****************************************************************************************************************/
//FUNÇÃO PARA IMPRIMIR A PALAVRA 
void imprimir_por_letra(arvore *R){
   arvore *aux1;//auxiliar tipo arvore
   lista *aux2;//auxiliar tipo arvore
   char letra;//
    
   printf("Digite a letra para a impressao :  ");
   fflush(stdin);
   letra = toupper(getchar());//ler a letra 

   aux1 = pesq_arvore(R,letra);//pesquisa se existe a letra na arvore
   if(aux1!=NULL){//caso aux1 for diferente de NULL quer dizer que existe a letra na arvore
      if(aux1->lista_palavra == NULL)//teste para verificar se existe alguma letra na arvore
         printf("\nNão existem palavras com a inicial %c nesse dicionario\n ",letra);
      else{//imrpimir a palavra com a sua descrição 
         aux2 = aux1->lista_palavra;//auxiliar vai receber o endereço da lista de palavra 
         printf("\n\n");
         printf("     %c\n\n",toupper(letra));//Imprimir
         printf("|---------------------------------------------------|\n");
         printf(" \tPalavra              \tDescricao                   \n");
         printf("|---------------------------------------------------|\n");
         while (aux2!= NULL){//Se existi mais de uma palavra começada com a lentra acima, será impresso toda aqui
            printf("  \t%s                  \t%s                          \n",aux2->palavra,aux2->descri);
            aux2 = aux2->prox;
              }
        }

     }
     else  printf("\n  Não existem palavras com a inicial %c nesse dicionario \n",letra);
}
/*****************************************************************************************************************/
//MENU MANTER : O USUÁRIO PODERÁ EXCLUIR, ALTERAR E INSERIR DE ACORDO COM SUA NECESSIDADE 
void Menu_Manter(arvore *ABC){
   int op;//variável que vai receber a opção do usuario
   int resb;
   char palavra[10],resp;
   do{
      system("cls");
      printf("\nDICIONARIO ABC\n\n");
      printf("\nMENU MANTER DICIONARIO\n\n");
      printf("[ I ] Inserir palavras\n");
      printf("[ L ] Listar palavras\n");
      printf("[ A ] Alterar palavras \n");
      printf("[ E ] Excluir palavras \n");
      printf("[ P ] Menu Principal\n");

      printf("\n\nopcao : ");
      fflush(stdin);
      op = toupper(getch());//receber a opção do usuario em letra maiúscula

     switch (op){
        case 'I' ://Quando entrar nessa condição pedirá a paralvra a ser inserida 
           ABC =pesq_inserir(ABC);// função que pesquisa se a palavra já existe e isere caso o usuário digite a descrição 
           system("pause");
           Menu_principal(ABC);//Retorna ao menu principal;
           break;
        case 'L' ://condição para entrar chamar o menu listar onde la encontrará duas forma de lista as palavras 
           Menu_listar(ABC);//função manter lista 
           break;
        case 'A' ://caso o usuário digite A, será pedido a palavra que deseja altera-la
           ABC = Alterar(ABC);//Função para alterar a palavra 
           system("pausenull");
           Menu_principal(ABC);//Retorna a menu principal
           break;
        case 'E' ://Qando entra nessa condição o usuario deseja excluir uma palavra
           printf("\nDigite a palavra a ser excluida : ");
           fflush(stdin);
           gets(palavra);//receber a palavra que o usuário deseja excluir
           strupr(palavra);//converte uma string para maiúsculas 
           ABC = excluir(ABC,palavra);//função para excluir a palavra
           resb = Altura_atualiza(ABC);//função para Atualizar o fator
           verifica(&ABC);//verificar se a arvore está balanceada se nao balanceia 
           resb = Altura_atualiza(ABC);//função para Atualizar o fator
           Menu_principal(ABC);//Retorna ao menu principal 
           break;
        case 'P' ://opção para retorna o menu principal 
           Menu_principal(ABC);//função para retorno do menu principal 
      }
   }while(op!='I' && op!='L' && op !='A' && op!='E'&& op!='P');//Um laço para fazer o usuário digitar uma das opções encotrada no menu
}

/*****************************************************************************************************************/
//MENU LISTA, TEM COMO FUNÇÃO LISTAR AS PALAVRAS POR COMEÇO DE LETRA OU TODAS PALAVRAS EXISTENTE 
void Menu_listar(arvore *ABC){//Função tipo Void 
   char op;//variável que vai receber a opção do usuario 
      
   do{
      system("cls");  
      printf("\nDICIONARIO ABC\n\n");
      printf("\nMENU LISTAR\n\n");
      printf("[ L ] Por letra _ apenas palavras que começam com um letra\n");
      printf("[ C ] Completo- todas palavras e suas descricoes\n");
      printf("[ M ] Menu manter dicionario \n");
      printf("[ P ] Menu Principal \n");

      printf("\n\nopcao : ");
      fflush(stdin);
      op = toupper(getch());//receber a opção do usuario em letra maiúscula  
     
      switch (op){//Condição para acessar  as impressões das palavras 
         case 'L': //Opção para imprimir por letra
            imprimir_por_letra(ABC);//Chama função para imprimir as palavras, por letra que o usuário desejar  
            system("pause");
            Menu_principal(ABC); //Retorna ao menu principal
            break;
         case 'C' ://Opção C irá imprimir todas as palavras 
            imprimir_completo(ABC);//Função que imprimi as palavras do dicionário 
            system("pause");
            Menu_principal(ABC);//Retorna ao menu principal
            break;
         case 'M' ://Opção M vai para função manter dicionário 
            Menu_Manter(ABC);
         case 'P' ://Opção P retorna ao menu principal
            Menu_principal(ABC);
      }
   }while(op!='L'&& op!='C' && op!='M' && op!='P');//Um laço para fazer o usuário digitar uma das opções encotrada no menu
}
/*****************************************************************************************************************/
//MENU PRINCIPAL: NELLE E ENCONTRADO OPÇÕES PARA ACESSAR AS PALAVRAS, MATER O DICIONARIO E SAIR
void Menu_principal(arvore *ABC){
   lista *auxi;//auxiliar para imprimir a palavra quando o usuário optar por Pesquisar palavra 
   char op;///variável que vai receber a opção do usuario 
   char palavra[15];//receber a palavra 
      
   do{                                                 
      system("cls");
      printf("\nDICIONARIO ABC\n\n");
      printf("\n***MENU PRINCIPAL***\n\n");
      printf("[ P ] Pesquisar Palavras\n");
      printf("[ M ] Manter dicionario\n");
      printf("[ S ] Sair do Sistema \n");

      printf("\n\nopcao : ");
      fflush(stdin);
      op = toupper(getch());//receber a opção do usuario em letra maiúscula  

      switch (op){
         case 'P' ://Ao escolher essa opção o usuário irá digita a palavra que necessita pesquisar, logo o programa irá imprimi se existe ou nao, se existi imprime a palavra com descrição 
            printf("\n\nDigite a palavra a ser pesquisada : ");
            fflush(stdin);
            gets(palavra);//receber o palavra
            strupr(palavra);//converte uma string para maiúsculas 
            auxi = imprimir_palavra(ABC,palavra);//imprimir a palavra
            system("pause");
            Menu_principal(ABC);//Retorna no menu principal 
            break;
         case 'M' ://Chama a função do menu manter, onde o usuario poderá iserir, excluir e alterar a palavra
            Menu_Manter(ABC);
       }
   }while(op!='P' && op!='M' && op!='S' );//Um laço para fazer o usuário digitar uma das opções encotrada no menu

}

/*****************************************************************************************************************/
//FUNÇÃO PRINCIPAL
int main(){

       arvore *ABC;//declaração da arvore
       ABC = inicializa(ABC);//inicialização da arvore

       Menu_principal(ABC);//chamando o menu principal 

       printf("Obrigado pela preferencia\nExecute sempre %c\n",3);//Agradecimento 


       system("pause");
        return 0;
}