Carregar apresentação
A apresentação está carregando. Por favor, espere
PublicouMaria Antonieta Castanho Carmona Alterado mais de 6 anos atrás
1
CES-11 ALGORITMOS E ESTRUTURAS DE DADOS Aulas Práticas – 2017
Capítulo IV Árvores Binárias
2
O programa a ser desenvolvido neste capítulo irá:
Montar a árvore binária para uma expressão aritmética Calcular o valor dessa expressão, percorrendo sua árvore em profundidade
3
Exemplo:
4
O programa terá os seguintes passos principais:
A expressão será digitada numa forma parentética apropriada A forma parentética será convertida em polonesa A polonesa será percorrida do final ao início, para a construção da árvore binária correspondente A árvore binária será percorrida para o cálculo de seu valor
5
Exemplo simples: Digitação da expressão em forma parentética: ((( ) * (8 + (53 * 12))) + 42) Conversão de parentética para polonesa: * + *
6
Construção da árvore binária a partir da polonesa:
* + * +
7
Construção da árvore binária a partir da polonesa:
* + * + 42
8
Construção da árvore binária a partir da polonesa:
* + * + * 42
9
Construção da árvore binária a partir da polonesa:
* + * + * 42 +
10
Construção da árvore binária a partir da polonesa:
* + * + * 42 + *
11
Construção da árvore binária a partir da polonesa:
* + * + * 42 + * 12
12
Construção da árvore binária a partir da polonesa:
* + * + * 42 + * 53 12
13
Construção da árvore binária a partir da polonesa:
* + * + * 42 + 8 * 53 12
14
Construção da árvore binária a partir da polonesa:
* + * + * 42 + + 8 * 53 12
15
Construção da árvore binária a partir da polonesa:
* + * + * 42 + + 90 8 * 53 12
16
Construção da árvore binária a partir da polonesa:
* + * + * 42 + + 23 90 8 * 53 12
17
Cálculo do valor da expressão na árvore binária:
int ValExpressao (arvbin A) { caso a raiz de A seja: { número: retornar o valor do número; operador: caso o operador seja: { ‘+’: retornar ValExpressao (A->fesq) + ValExpressao (A->fdir); ‘*’: retornar ValExpressao (A->fesq) * }
18
(((n1 + n2) * (n3 + (n4 * n5))) + n6)
Exercício 4.1: Obtenção dos átomos de uma expressão aritmética Sejam expressões do tipo: (((n1 + n2) * (n3 + (n4 * n5))) + n6) também chamadas expressões na forma parentética, onde ni é um número inteiro não negativo com um ou mais dígitos decimais os operadores são somente ‘+’ e ‘*’ todas as operações são colocadas entre parênteses
19
(((n1 + n2) * (n3 + (n4 * n5))) + n6)
Átomos de uma expressão como essas são os seus números, seus operadores e seus parêntesis. Um átomo é uma entidade contendo dois campos: o tipo e um eventual atributo. Um átomo pode ser de um dos seguintes tipos: NUMERO: quando ele for um número inteiro OPERADOR: quando ele for um dos caracteres ‘+’ ou ‘*’ ABPAR: quando ele for o caractere ‘(’ FPAR: quando ele for o caractere ‘)’ INVAL: quando ele for qualquer outro caractere
20
(((n1 + n2) * (n3 + (n4 * n5))) + n6)
O eventual atributo de um átomo depende de seu tipo: NUMERO: o atributo é o valor numérico do número OPERADOR: o atributo é o próprio caractere ‘+’ ou ‘*’ ABPAR: o átomo não precisa de atributo FPAR: o átomo também não precisa de atributo INVAL: o atributo é o próprio caractere Declarações para átomos: typedef struct atomo atomo; typedef union atribatomo atribatomo; union atribatomo { int valor; char oper, carac;}; struct atomo { int tipo; atribatomo atrib;};
21
Exemplo: átomos da expressão ((35 + 62) * 7)
tipo ABPAR atrib tipo ABPAR atrib tipo NUMERO atrib / valor 35 tipo OPERADOR atrib / oper + tipo NUMERO atrib / valor 62 tipo FPAR atrib tipo OPERADOR atrib / oper * tipo NUMERO atrib / valor 7 tipo FPAR atrib typedef struct atomo atomo; typedef union atribatomo atribatomo; union atribatomo { int valor; char oper, carac;}; struct atomo { int tipo; atribatomo atrib;};
22
Trabalho a fazer: completar o esqueleto de programa a seguir que:
Lê uma expressão na forma parentética Encontra seus átomos (tipos e atributos), guardando-os num vetor de átomos Escreve no vídeo o conteúdo desse vetor.
23
/* Biblioteca utilizada da linguagem */
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <ctype.h> /* Constantes simbolicas gerais */ #define logic char #define TRUE 1 #define FALSE 0 /* Constantes simbolicas para os tipos dos atomos */ #define NUMERO 1 #define OPERADOR 2 #define ABPAR 3 #define FPAR 4 #define INVAL 5
24
Parentetica: vetor de átomos para armazenar os átomos da expressão
/* Declaracoes de tipos */ typedef char expressao[100]; typedef struct atomo atomo; typedef union atribatomo atribatomo; union atribatomo {int valor; char oper, carac;}; struct atomo {int tipo; atribatomo atrib;}; /* Variaveis globais */ atomo Parentetica[100]; int nparent, i; char c; expressao expr; Parentetica: vetor de átomos para armazenar os átomos da expressão nparent: número atual de átomos em Parentetica expr: vetor de caracteres com a expressão i: cursor para percorrer expr c: guarda um caractere de expr
25
GetNonBlank: procura o próximo caractere não-branco em expr
/* Prototipos das funcoes auxiliares */ void FormarAtomos (void); void EscreverAtomos (int, atomo[]); char GetNonBlank (void); char GetNext (void); void InicExpr (void); FormarAtomos: encontra todos os átomos de expr e os armazena em Parentetica EscreverAtomos: escreve na tela o conteúdo de todos os átomos em um vetor de átomos GetNonBlank: procura o próximo caractere não-branco em expr GetNext: retorna o próximo caractere de expr InicExpr: posiciona o cursor i no primeiro caractere de expr
26
/* Funcao main */ int main() { char c; printf ("Encontrar atomos de expressao? (s/n): "); do c = getche ( ); while (c!='s' && c!='n' && c!='S' && c!='N'); while (c == 's' || c == 'S') { clrscr (); printf ("Digite a expressao: "); setbuf (stdin, NULL); gets (expr); FormarAtomos (); printf ("\nAtomos da expressao:\n"); EscreverAtomos (nparent, Parentetica); printf ("\n\nEncontrar atomos de nova expressao? (s/n): "); } clrscr (); printf ("Fim das atividades!"); printf ("\n\n"); system ("pause"); return 0;
27
A função FormarAtomos poderá seguir as seguintes diretrizes:
void FormarAtomos () { Zerar o número de átomos encontrados; Posicionar o cursor da expressão em seu início; Procurar o primeiro caractere não branco; enquanto esse caractere não for o ‘\0’ { Inserir um novo átomo em Parentetica, conforme o valor desse caractere; Caso seja dígito { } Caso seja '+' ou '*' { } Caso seja '(' ou ')' { } Caso seja qualquer outro caractere { } Acrescentar uma unidade ao número de átomos encontrados; Procurar o próximo caractere não branco; }
28
Caso seja dígito { Coletar os outros dígitos; O tipo do átomo é NUMERO; O atributo é o valor numérico da cadeia formada pelos dígitos coletados; } Caso seja '+' ou '*' { O tipo do átomo é OPERADOR; O atributo é o próprio caractere; Caso seja '(' ou ')' { O tipo do átomo é respectivamente ABPAR ou FPAR; O atributo não é necessário; Caso seja qualquer outro caractere { O tipo do átomo é INVAL;
29
Para uma expressão tal como
( ( )*13 & + 43;) ) a função EscreverAtomos deverá mostrar na tela uma tabela semelhante à seguinte: Atomos da expressao: TIPO | ATRIBUTO ABPAR | NUMERO | 12 OPERADOR | + NUMERO | 32 FPAR | OPERADOR | * NUMERO | 13 INVAL | & NUMERO | 43 INVAL | ;
30
/* Funcoes para percorrer a expressao */
char GetNonBlank ( ) { while (isspace (expr[i]) || (iscntrl (expr[i]) && expr[i] != '\0')) i++; return expr[i]; } char GetNext () { i++; void InicExpr ( ) { i = 0;
31
Exercício 4.2: Verificar se um vetor de átomos guarda a forma parentética de uma expressão, usando a seguinte definição recursiva: Sendo m e n dois números inteiros não negativos com um ou mais dígitos cada, (m + n) e (m * n) são expressões na forma parentética. Sendo α e β números inteiros não negativos ou expressões na forma parentética, (α + β) e (α * β) também são expressões nessa forma. É necessário adaptar essa definição a expressões compostas de átomos, conforme definido no exercício anterior.
32
Exercício 4.3: Transformar parentética em polonesa
Obter um vetor de átomos correspondente à polonesa de uma expressão guardada num vetor de átomos, na forma parentética Exemplo: seja a seguinte forma parentética: ((( ) * (8 + (53 * 12))) + 42) Sua polonesa correspondente: * + *
33
Método de transformação:
Percorrer o vetor da parentética; Ao encontrar um número, inseri-lo no final da polonesa Ao encontrar um operador, colocá-lo numa pilha de átomos; Ao encontrar um abre-parêntesis, nada fazer; Ao encontrar um fecha parêntesis, desempilhar um operador e colocá-lo no final da polonesa Sugestão: montar a polonesa durante o teste da parentética (Exercício 4.2)
34
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) Parentética Polonesa
Pilha de operadores
35
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) Parentética Polonesa
Pilha de operadores
36
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) Parentética Polonesa
Pilha de operadores
37
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 Parentética
Polonesa 23 Pilha de operadores
38
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 Parentética
Polonesa 23 + Pilha de operadores
39
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 Parentética
Polonesa 23 90 + Pilha de operadores
40
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + Parentética
Polonesa Pilha de operadores
41
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + Parentética
Polonesa * Pilha de operadores
42
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + Parentética
Polonesa * Pilha de operadores
43
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 Parentética
Polonesa * Pilha de operadores
44
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 Parentética
Polonesa + * Pilha de operadores
45
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 Parentética
Polonesa + * Pilha de operadores
46
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 53
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa + * Pilha de operadores
47
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 53
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * Pilha de operadores
48
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 53 12
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * Pilha de operadores
49
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 53 12 *
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * Pilha de operadores
50
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 53 12 * +
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * Pilha de operadores
51
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 53 12 * + *
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * Pilha de operadores
52
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42) 23 90 + 8 53 12 * + *
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * + Pilha de operadores
53
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42)
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * 42 + Pilha de operadores
54
Simulação: (((23 + 90) * (8 + (53 * 12))) + 42)
Parentética ((( ) * (8 + (53 * 12))) + 42) Polonesa * + * 42 + Pilha de operadores
55
Declarações e protótipos para o TAD Pilha (estrutura encadeada):
typedef struct noh noh; typedef noh *pilha; struct noh {atomo elem; noh *prox;}; void Empilhar (atomo, pilha*); void Desempilhar (pilha*); atomo Topo (pilha); void InicPilha (pilha*); logic Vazia (pilha);
56
Funções-operadores para o TAD Pilha (estrutura encadeada):
void Empilhar (atomo x, pilha *P) { noh *temp; temp = *P; *P = (noh *) malloc (sizeof (noh)); (*P)->elem = x; (*P)->prox = temp;} void Desempilhar (pilha *P) { noh *temp; if (! Vazia(*P)) {temp = *P; *P = (*P)->prox; free (temp); } } atomo Topo (pilha P) {if (! Vazia(P)) return P->elem;} void InicPilha (pilha *P) { *P = NULL; } logic Vazia (pilha P) { if (P == NULL) return TRUE; else return FALSE; }
57
Exercício 4.4: Construir uma árvore binária para a expressão, a partir da polonesa
Exemplo: Polonesa * + * 42 + Árvore binária
58
Declarações para árvore binária:
typedef struct celula celula; typedef celula *noharvbin; typedef celula *arvbin; struct celula {atomo elem; celula *pai, *fesq, *fdir;}; arvbin Arv; elem (atomo) pai fesq fdir celula Arv Árvore binária
59
Exercício 4.5: Escrever a forma parentética original da expressão, a partir da árvore binária
Diretriz: percorrer a árvore binária em ordem-central, escrevendo os atributos dos nós e escrevendo parêntesis em momentos oportunos
60
Exercício 4.6: Calculo do valor da expressão na árvore binária:
Diretrizes: int ValExpressao (arvbin A) { caso a raiz de A seja: { número: retornar o valor do número; operador: caso o operador seja: { ‘+’: retornar ValExpressao (A->fesq) + ValExpressao (A->fdir); ‘*’: retornar ValExpressao (A->fesq) * }
61
Exercício 4. 7: Estender o programa do Exercício 4
Exercício 4.7: Estender o programa do Exercício 4.6 para trabalhar com números reais Aceitar como número uma cadeia que comece com um ou mais dígitos, seguidos opcionalmente por um ponto e zero ou mais dígitos Exercício 4.8: Estender o programa do Exercício 4.7 para trabalhar com os operadores binários ‘-’ (subtração) e ‘/’ (divisão)
62
Exercício 4. 9: Estender o programa do Exercício 4
Exercício 4.9: Estender o programa do Exercício 4.8 para trabalhar com os seguintes operadores: ~: menos unário @: potenciação L: logaritmo R: raiz quadrada S: seno C: cosseno
63
Exemplos de expressões parentéticas e polonesas usando esses operadores:
Apresentações semelhantes
© 2024 SlidePlayer.com.br Inc.
All rights reserved.