| Linha | Codigo |
| 001 | // Prof. Leo^nidas - http://www.matematica.br http://line.ime.usp.br |
| 002 | // MAC0122 - 2017/10/08 |
| 003 | // Primeira versao de: 2003 |
| 004 | |
| 005 | // Exemplo de: arvore binaria (AB); expressao aritmetica (EA) em notacao in-fixa; expressao em notacao pos-fixa; listas ligadas |
| 006 | // Descricao: Constroi uma AB representando uma Ea, depois a avalia de 2 modos (iterativo e recursivo) |
| 007 | |
| 008 | // gcc -fsanitize=address -g -o arvore_bin_expressao_aleatoria arvore_bin_expressao_aleatoria.c |
| 009 | |
| 010 | #include <stdio.h> |
| 011 | #include <stdlib.h> |
| 012 | |
| 013 | #define MAX 2 // maxima profundidade da arvore |
| 014 | #define Infimo 1 // so' aceita "operando" apos nivel 1 |
| 015 | #define MAXREC 30 // tamanho maximo para a pilha |
| 016 | #define RESTO 5 // fator para diminuir valor dos numeros gerados |
| 017 | #define SEMENTE 11 // para geracao de numeros aleatorios |
| 018 | |
| 019 | typedef struct Filho { |
| 020 | struct Filho *esq; |
| 021 | char tipo; |
| 022 | union { char c; int i; } info; // se tipo='d' => <operador => usar 'char c'>; se tipo='n' => <operando => usar 'int i'> |
| 023 | struct Filho *dir; |
| 024 | } No; |
| 025 | |
| 026 | int topo_ap, topo_v; // para simplificar usarei como globais (CUIDADO: evite, pois gera dificuldades de manutencao) |
| 027 | |
| 028 | // Prototipos de funcoes |
| 029 | void imprime_arvore(No *r, int col); |
| 030 | No *adiciona_filho(int cont); |
| 031 | void monta_exp(No **) |
| 032 | //V2 No *monta_exp(void); |
| 033 | |
| 034 | // Imprime arvore usando deslocanmento horizontal para indicar maior profundidade |
| 035 | void imprime_arvore (No *r, int col) { // col indica profundidade do no' |
| 036 | int aux; |
| 037 | if ( r!= NULL ) { |
| 038 | if ( (*r).dir!=NULL ) imprime_arvore( (*r).dir, col+1 ); |
| 039 | for (aux=0; aux<col; aux++) |
| 040 | printf(" "); |
| 041 | if ((*r).tipo=='d') printf("%c\n",(*r).info.c); |
| 042 | else printf("%d\n",(*r).info.i); |
| 043 | if ( (*r).esq!=NULL ) imprime_arvore( (*r).esq, col+1); |
| 044 | } |
| 045 | } |
| 046 | |
| 047 | // Constroi arvore usando apenas operadores '*' e '+' |
| 048 | No *adiciona_filho (int cont) { |
| 049 | No *aux; |
| 050 | int aux1, aux2, n; char c; |
| 051 | aux = malloc(sizeof(No)); |
| 052 | if (cont<MAX) { // dentro do limite de profundidade |
| 053 | // Para GCC: aux1 = rand()%2; // 0 => operador, 1 => operando |
| 054 | aux1 = (int)(rand()%2); // 0 => operador, 1 => operando |
| 055 | if (aux1 && cont>Infimo) { |
| 056 | // e' operando |
| 057 | n = (rand() % RESTO); |
| 058 | if (n==0) n = 1; // evita 0 (0*n=0) |
| 059 | (*aux).info.i = n; |
| 060 | (*aux).tipo = 'n'; |
| 061 | (*aux).esq = NULL; |
| 062 | (*aux).dir = NULL; |
| 063 | } |
| 064 | else { // else de if (aux1 && cont>Infimo) |
| 065 | // e' operador |
| 066 | aux2 = rand()%2; // 0 => '+', 1 => '*' |
| 067 | if (aux2) |
| 068 | c='*'; |
| 069 | else |
| 070 | c='+'; |
| 071 | (*aux).info.c = c; |
| 072 | (*aux).tipo = 'd'; |
| 073 | // e' operador => tem dois filhos |
| 074 | (*aux).esq = adiciona_filho( cont+1 ); |
| 075 | (*aux).dir = adiciona_filho( cont+1 ); |
| 076 | } // else |
| 077 | } // if (cont<MAX) |
| 078 | else { // ja' atingiu o limite de profundidade, forca ser operando |
| 079 | printf("ultimo cont=%d MAX=%d\n",cont,MAX); |
| 080 | n = (rand() % RESTO); |
| 081 | if (n==0) n = 1; // evita 0 (0*n=0) |
| 082 | (*aux).info.i = n; |
| 083 | (*aux).tipo = 'n'; |
| 084 | (*aux).esq = NULL; |
| 085 | (*aux).dir = NULL; |
| 086 | } // else if (cont<MAX) |
| 087 | return aux; |
| 088 | } // adiciona_filho |
| 089 | |
| 090 | //V2 No *monta_exp (void) |
| 091 | void monta_exp (No **r) { |
| 092 | //V2 No *r; |
| 093 | int aux1; char c; |
| 094 | *r = malloc(sizeof(No)); // no' r aponta para novo no' |
| 095 | srand(SEMENTE); |
| 096 | aux1 = rand() % 2; // 0 => '+', 1 => '*' |
| 097 | if (aux1) // decide operador: '+' ou '*' |
| 098 | c='*'; |
| 099 | else |
| 100 | c='+'; |
| 101 | (**r).info.c = c; |
| 102 | (**r).tipo = 'd'; |
| 103 | (**r).esq = adiciona_filho(0); |
| 104 | (**r).dir = adiciona_filho(0); |
| 105 | printf("\n retornou \n"); |
| 106 | //V2 return r; |
| 107 | } |
| 108 | |
| 109 | // Calcula valor da expressao de modo iterativo |
| 110 | int Calc_exp_it (No *r) { |
| 111 | No *Ap[MAXREC], *pai, *aux; |
| 112 | int V[MAXREC], topo_ap, topo_v, aux_esq, aux_dir; |
| 113 | |
| 114 | // auxiliar para termino do algoritmo |
| 115 | aux = malloc(sizeof(No)); |
| 116 | (*aux).esq = (*aux).dir=NULL; |
| 117 | topo_ap = topo_v = -1; |
| 118 | Ap[++topo_ap] = aux; |
| 119 | while (r!=NULL) { |
| 120 | if ((*r).tipo=='d') { // e' operador => empilhe |
| 121 | Ap[++topo_ap] = r; |
| 122 | pai = r; |
| 123 | r = (*r).esq; |
| 124 | } |
| 125 | else // e' operando => desempilhe 2 |
| 126 | if (r==(*pai).dir) { // e' filho direito => computa expressao |
| 127 | V[++topo_v] = (*r).info.i; |
| 128 | while (r==(*pai).dir) { // pegue 3 do topo da pilha e opere: operador operando1 operando2 => operando1 operador operando2 = operando3 |
| 129 | aux_dir = V[topo_v--]; |
| 130 | aux_esq = V[topo_v]; |
| 131 | if ((*pai).info.c=='+') |
| 132 | V[topo_v] = aux_dir + aux_esq; // empilhe 'operando3' |
| 133 | else |
| 134 | V[topo_v] = aux_dir * aux_esq; // empilhe 'operando3' |
| 135 | r = pai; |
| 136 | pai = Ap[--topo_ap]; |
| 137 | } |
| 138 | r = (*pai).dir; |
| 139 | } // if (r==(*pai).dir) |
| 140 | else { // e' filho esquerdo |
| 141 | V[++topo_v] = (*r).info.i; |
| 142 | r = (*pai).dir; |
| 143 | } |
| 144 | } // while |
| 145 | |
| 146 | return V[0]; |
| 147 | } |
| 148 | |
| 149 | // Calcula expressao de modo recursivo |
| 150 | int Calc_exp_rec (No *r) { |
| 151 | int aux_esq, aux_dir; |
| 152 | if (r!=NULL) |
| 153 | if ( (*r).tipo=='d' ) { // e' operador |
| 154 | aux_esq = Calc_exp_rec( (*r).esq ); |
| 155 | aux_dir = Calc_exp_rec( (*r).dir ); |
| 156 | if ( (*r).info.c=='+' ) |
| 157 | return aux_esq + aux_dir; |
| 158 | else |
| 159 | return aux_esq * aux_dir; |
| 160 | } |
| 161 | else |
| 162 | return (*r).info.i; |
| 163 | else |
| 164 | return 0; // --> so' sera' necessario se a arv. for vazia! |
| 165 | } |
| 166 | |
| 167 | // |
| 168 | void main (void) { |
| 169 | No *raiz; |
| 170 | |
| 171 | printf("INICIO\n"); |
| 172 | |
| 173 | //V2 raiz=monta_exp(); |
| 174 | monta_exp(&raiz); |
| 175 | |
| 176 | imprime_arvore(raiz, 0); |
| 177 | |
| 178 | printf("\nValor (iterativo) %d\n",Calc_exp_it(raiz)); |
| 179 | printf("\nValor (recursivo) %d\n",Calc_exp_rec(raiz)); |
| 180 | } |