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 | } |