fabi2295

Árvore

Jun 2nd, 2016
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.09 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5.  
  6. #define FOLHA       (Folha)malloc(sizeof(struct folha))
  7. #define CMDSTR      500
  8.  
  9. typedef struct folha* Folha;
  10.  
  11. struct folha {
  12.     int info;
  13.  
  14.     Folha   esquerda;
  15.     Folha   direita;
  16. };
  17.  
  18. Folha inserir (Folha, int), deletar (Folha, int), procurar (Folha, int);
  19. void imprimir_arvore (Folha, int);
  20. void ordenada(Folha), preordenada(Folha), posordenada(Folha);
  21. void cmd (void), help (void);
  22.  
  23. /* @ Folha inserir (Folha raiz, int info)
  24.  *
  25.  * Argumentos
  26.  * ----------
  27.  *  raiz    ponteiro para 'struct folha', estrutura de dado básica para
  28.  *      construção da árvore
  29.  *  info    nova informação a ser inserida
  30.  *
  31.  * Retorno
  32.  * -------
  33.  *  NULL    em caso de erro
  34.  *  Folha   em caso de sucesso (nó 'raiz')
  35.  */
  36. Folha inserir (Folha raiz, int info)
  37. {
  38.     if (!raiz) {
  39.         /* significa que o ponteiro é nulo, e que está é a posição
  40.          * para inserção.
  41.          *
  42.          * 1. Alocar e checar memória
  43.          */
  44.         if (!(raiz = FOLHA)) {
  45.             perror("inserir:malloc()");
  46.             return NULL;
  47.         }
  48.  
  49.         /* 2. Cópia da Informação
  50.          * 3. Ponteiros de referência
  51.          * 4. Retorno da nova folha
  52.          */
  53.         raiz->info = info;
  54.         raiz->esquerda = raiz->direita = NULL;
  55.  
  56.         return raiz;
  57.     } else if (info > raiz->info)
  58.         raiz->direita = inserir (raiz->direita, info);
  59.     else
  60.         raiz->esquerda = inserir (raiz->esquerda, info);
  61.  
  62.     /* retorna o ponteiro raiz
  63.      *
  64.      * Isso é necessário pois a função inserir é recursiva, e seu retorno
  65.      * é sempre atribuido ao mesmo ponteiro passado como argumento 'raiz',
  66.      *
  67.      * raiz->esquerda = inserir(raiz->esquerda,info)
  68.      * raiz->direita  = inserir(raiz->direta,  info)
  69.      */
  70.     return raiz;
  71. }
  72.  
  73. /* @ Folha deletar (Folha raiz, int info)
  74.  *
  75.  * Argumentos
  76.  * ----------
  77.  *  raiz    raiz principal da arvore
  78.  *  info    informação procurada para deletar
  79.  *
  80.  *  Retorno
  81.  *  -------
  82.  *  raiz    em ambos os casos
  83.  */
  84. Folha deletar (Folha raiz, int info) {
  85.     /* para deletar um nó, é necessário que esse nó exista.
  86.      * Então, vamos procurar pelo nó.
  87.      *
  88.      * A remoção de folhas em uma árvore é um pouco mais detalhada que sua
  89.      * similar para listas encadeadas.
  90.      *
  91.      * Existem alguns pontos a se considerar para remover uma folha:
  92.      *  1. A folha é também uma raiz (contém subárvores)?
  93.      *  2.
  94.      */
  95.     Folha filho, n_raiz;
  96.  
  97.     /* se chegou ao final da arvore e nao encontrou nada para deletar....
  98.      */
  99.     if (!raiz) return NULL;
  100.  
  101.     /* primeira comparação do programa:
  102.      *  Achamos a informação procurada?
  103.      */
  104.     if (raiz->info == info) {
  105.         /* 1. Existe uma raiz direita?
  106.          *  (uma raiz direita contém todos os elementos MAIORES que
  107.          *  a raiz que estamos excluindo).
  108.          *
  109.          * 2. Caso ela exista, ela será a nova raiz.
  110.          * 3. Os atuais elementos *menores* deverão ser anexados nos
  111.          *    menores elementos da nova raiz (segundo passo).
  112.          */
  113.         if (raiz->direita) {
  114.             /* 2. a nova raiz é a subárvore da direita, que contem
  115.              * todos os elementos MAIORES que a raiz a ser removida
  116.              */
  117.             n_raiz = filho = raiz->direita;
  118.  
  119.             /* 3. a subárvore esquerda da nova raíz é percorrida
  120.              * até onde não houverem mais elementos. Isso nos dará
  121.              * o menor elemento maior que a folha esquerda de nossa
  122.              * raiz a ser removida.
  123.              */
  124.             while(filho->esquerda)
  125.                 filho = filho->esquerda;
  126.  
  127.             /* o menor elemento maior que a raiz
  128.              * torna-se
  129.              * raiz de todos os elementos menores que a raiz
  130.              * removida
  131.              */
  132.             filho->esquerda = raiz->esquerda;
  133.  
  134.             /* libera a memória do ponteiro */
  135.             free (raiz);
  136.  
  137.             /* 1 + 2: nova raiz */
  138.             return n_raiz;
  139.  
  140.         } else {
  141.             /* caso não haja uma raiz direita (elementos MAIORES)
  142.              * que nossa raiz, a nova raiz da árvore seja o único
  143.              * elemento restante: a subárvore esquerda da árvore,
  144.              * ou os antigos elementos menores que a raiz removida.
  145.              */
  146.             n_raiz = raiz->esquerda;
  147.  
  148.             /* libera a memória do ponteiro */
  149.             free (raiz);
  150.  
  151.             /* retorno da nova raiz */
  152.             return n_raiz;
  153.         }
  154.  
  155.     } else if (info > raiz->info) {
  156.         /* Caso a informação procurada seja maior que a informação na
  157.          * raiz, devemos então procurar pela informação na subárvore
  158.          * da direita (esta operação deverá ser congruente em todo o
  159.          * seu programa.
  160.          *
  161.          * Você não pode ordenar a inserção de um jeito e a remoção de
  162.          * outro!
  163.          */
  164.         raiz->direita = deletar(raiz->direita, info);
  165.     } else {
  166.         /* Caso a informação seja menor que a raiz, procuraremos por ela
  167.          * nas subárvores da esquerda.
  168.          */
  169.         raiz->esquerda = deletar(raiz->esquerda, info);
  170.     }
  171.     /* Lembre-se que as árvores binárias são estruturas de dados recursivas,
  172.      * e por esse motivo, é sempre bom saber o que se está retornando.
  173.      *
  174.      * Assim como na função de inserção, as chamadas recursivas à deletar()
  175.      * esperam como retorno uma raíz! Para onde a raiz->esquerda vai
  176.      * apontar quando a função retornar?
  177.      *
  178.      *  1. Se ela não for excluida, vai ser a própria raiz->esquerda
  179.      *  2. Caso seja excluída, será determinada pelo algoritmo no bloco
  180.      *     if(raiz->info == info).
  181.      *
  182.      * Aqui, no final do escopo da função, significa que é um retorno de
  183.      * chamadas recursivas à deletar (já que o bloco raiz->info == info)
  184.      * retorna por si só. Já que este é um retorno das chamadas recursivas,
  185.      * deve retornar a raiz na qual foi chamada.
  186.      */
  187.     return raiz;
  188. }
  189.  
  190. Folha procurar (Folha raiz, int info)
  191. {
  192.     /* como todas as funções relativas a arvores binárias são recursivas,
  193.      * todas necessitam de um parametro de "parada de recursão", então,
  194.      * sempre que acharmos um nó NULO, retornamos (até porque não dá pra
  195.      * imprimir informações de um nó que não existe.
  196.      */
  197.     if (!raiz) return NULL;
  198.  
  199.     if (info > raiz->info) return procurar(raiz->direita, info);
  200.     else return procurar (raiz->esquerda, info);
  201.  
  202.     /* falhas, compilação, etc */
  203.     return NULL;
  204. }
  205.  
  206. void imprimir_arvore (Folha raiz, int level)
  207. {
  208.     register int i;
  209.  
  210.     /* como todas as funções relativas a arvores binárias são recursivas,
  211.      * todas necessitam de um parametro de "parada de recursão", então,
  212.      * sempre que acharmos um nó NULO, retornamos (até porque não dá pra
  213.      * imprimir informações de um nó que não existe.
  214.      */
  215.     if (!raiz) return ;
  216.  
  217.     /* essa função é uma derivação da ordenação 'inorder', onde primeiro
  218.      * a arvore é percorrida até seu elemento mais esquerdo, e então é
  219.      * impressa a informação da raiz, e então é percorrida suas subárvores
  220.      * direitas.
  221.      *
  222.      * para imprimir de forma 'didática', essa função viaja primeiro pelas
  223.      * folhas direitas, imprime a raiz e então percorre as subárvores
  224.      * esquerdas.
  225.      */
  226.     imprimir_arvore (raiz->direita, level + 1);
  227.  
  228.     for (i = 0; i < level * 2; i++ ) putchar(' ');
  229.     printf("%d
  230. ", raiz->info);
  231.  
  232.     imprimir_arvore (raiz->esquerda, level + 1);
  233. }
  234.  
  235. /* @ void ordenada (Folha raiz)
  236.  *
  237.  * Transversalização Ordenada
  238.  * --------------------------
  239.  * Primeiro é visitada a subárvore esquerda, depois a raiz e por último a
  240.  * subárvore direita.
  241.  */
  242. void ordenada (Folha raiz)
  243. {
  244.     if (!raiz) return ;
  245.  
  246.     ordenada (raiz->esquerda);
  247.     printf ("%d ", raiz->info);
  248.     ordenada (raiz->direita);
  249. }
  250.  
  251. /* @ void preordenada (Folha raiz)
  252.  *
  253.  * Transversalização Pré-Ordenada
  254.  * ------------------------------
  255.  * Primeiro é visitada a raiz, depois a subárvore esquerda e por último a
  256.  * subárvore direita.
  257.  */
  258. void preordenada (Folha raiz)
  259. {
  260.     if (!raiz) return ;
  261.  
  262.     printf ("%d ", raiz->info);
  263.     preordenada (raiz->esquerda);
  264.     preordenada (raiz->direita);
  265. }
  266.  
  267. /* @ void posordenada (Folha raiz)
  268.  *
  269.  * Transversalização Pós-Ordenada
  270.  * ------------------------------
  271.  * Primeiro é visitada a subárvore esquerda, depois a subárvore direita e por
  272.  * último a raiz.
  273.  */
  274. void posordenada (Folha raiz)
  275. {
  276.     if (!raiz) return;
  277.  
  278.     posordenada (raiz->esquerda);
  279.     posordenada (raiz->direita);
  280.     printf ("%d ", raiz->info);
  281. }
  282.  
  283. /******************************************************************************
  284.  * Aqui termina todo o código relacionado às árvores binárias e começa o código
  285.  * relative à interface.
  286.  *
  287.  */
  288. void cmd (void)
  289. {
  290.     char cmd[CMDSTR], *arg;
  291.     Folha raiz = NULL;
  292.  
  293.     help();
  294.  
  295.     while (1) {
  296.         printf ("ArvoreBinaria> ");
  297.         fgets (cmd, CMDSTR, stdin);
  298.  
  299.         if (!cmd) continue;
  300.  
  301.         switch (*cmd) {
  302.         case 'i':
  303.             arg = &cmd[2];
  304.             arg = strtok(arg, " ");
  305.             while (arg) {
  306.                 if (!raiz) raiz = inserir (raiz, atoi(arg));
  307.                 else inserir (raiz, atoi(arg));
  308.  
  309.                 arg = strtok (NULL, " ");
  310.             }
  311.             break;
  312.         case 'd':
  313.             arg = &cmd[2];
  314.             arg = strtok(arg, " ");
  315.             while (arg) {
  316.                 raiz = deletar (raiz, atoi(arg));
  317.  
  318.                 arg = strtok (NULL, " ");
  319.             }
  320.             break;
  321.         case 'm':
  322.             imprimir_arvore (raiz, 0);
  323.             break;
  324.         case 'o':
  325.             ordenada(raiz);
  326.             puts("");
  327.             break;
  328.         case 'r':
  329.             preordenada(raiz);
  330.             puts("");
  331.             break;
  332.         case 'p':
  333.             posordenada(raiz);
  334.             puts("");
  335.             break;
  336.         case 's':
  337.             exit(0);
  338.         case 'h':
  339.             help();
  340.             break;
  341.         default:
  342.             printf("Comando nao reconhecido.
  343. ");
  344.             break;
  345.         }
  346.  
  347.         memset (cmd, 0x0, CMDSTR);
  348.     }
  349. }
  350.  
  351. /* @ void help (void)
  352.  *
  353. *   i 20    vai inserir o elemento 20 na árvore
  354.  *  d 20    vai remover o elemento 20 da árvore
  355.  *  m   vai mostrar a árvore na tela
  356.  *  o   transversalização ordenada
  357.  *  r   transversalização pré-ordenada
  358.  *  p   transversalização pós-ordenada
  359.  *  s   sai do programa
  360.  *  h   mostra a ajuda
  361.  */
  362. void help (void)
  363. {
  364.     printf ("    |    Arvores Binarias
  365. ");
  366.     printf ("    |    Implementacao em C para o Viva O Linux
  367. ");
  368.     printf ("    |    
  369. ");
  370.     printf ("    |    Autor: Enzo Ferber
  371. ");
  372.     printf ("    |    2015
  373. ");
  374.     printf ("    |
  375.  
  376. ");
  377.  
  378.     printf ("       Lista de comandos
  379. ");
  380.     printf ("       -----------------
  381. ");
  382.     printf ("       i %%d - Inserir um elemento
  383. ");
  384.     printf ("       d %%d - Deletar um elemento
  385. ");
  386.     printf ("       m    - Mostrar a arvore lateralmente
  387. ");
  388.     printf ("       o    - Transversalizacao Ordenada
  389. ");
  390.     printf ("       r    - Transversalizacao Pre-Ordenada
  391. ");
  392.     printf ("       p    - Transversalizacao Pos-Ordenada
  393. ");
  394.     printf ("       s    - Sair do programa
  395. ");
  396.     printf ("       h    - Mostra a ajuda
  397.  
  398. ");
  399. }
  400.  
  401. int main (void)
  402. {
  403.     cmd ();
  404.     return 0;
  405. }
Advertisement
Add Comment
Please, Sign In to add comment