aula 233

Como resolver expressão em notação pós-fixa (notação polonesa reversa)?

Na aula de hoje vamos ver mais uma aplicação prática para estruturas de dados dinâmicas do tipo pilha. Vamos aprender como resolver uma expressão em notação pós-fixa (notação polonesa reversa).

A notação pós-fixa ou notação polonesa reversa é uma forma diferente de escrever uma expressão matemática de tal forma que não há dúvida sobre qual operação deve ser realizada primeiro. Nesta notação os números sempre ficam à esquerda e a operação a ser realizada a direita. Veja a seguir alguns exemplos de expressões escritas na notação infixa e sua equivalente em notação pós-fixa.

    Notação Infixa                                 Notação Pós-fixa
    ( 51 + 13 * 12 )                               51 13 12 * +
    ( 5 * ( 3 + 2 ) / 4 - 6 )                      5 3 2 + * 4 / 6 -
    ( 5 + 3 + 2 * 4 - 6 * 7 * 1 )                  5 3 + 2 4 * + 6 7 * 1 * -
    ( 5 * ( 3 + ( 2 * ( 4 + ( 6 * ( 7 + 1 ))))))   5 3 2 4 6 7 1 + * + * + *

O objetivo neste exercício é resolver uma expressão digitada a partir do teclado em notação pós-fixa, então, vamos entender como resolver uma expressão desse tipo no papel para depois programar o computador. Vamos avaliar o segundo exemplo: 5 3 2 + * 4 / 6 –

Para resolver esta equação, vamos procurar pela primeira operação matemática, da esquerda para a direita, e resolvê-la, lembrando que a operação está sempre à direita dos números. Assim, a primeira operação a ser a realizada é a soma de 3 e 2. Ao realizar esta soma, a expressão resultando é: 5 5 * 4 / 6 –

Agora, a próxima operação a ser realizada é a multiplicação de 5 e 5 chegando a: 25 4 / 6 –

A seguir temos a resolução completa da expressão: 5 3 2 + * 4 / 6 –
5 3 2 + * 4 / 6 –
5 5 * 4 / 6 –
25 4 / 6 –
6.25 6 –
0.25

Tente resolver os outros três exemplos, isso vai ajudar a fixar a ideia.

Como resolver uma expressão em notação pós-fixa

A princípio pode parecer complicado resolver este problema, mas não é. Com uma estrutura de dados do tipo pilha a solução fica bastante simples.

Como já foi mencionado, os números estão sempre à esquerda da operação. Assim, podemos percorrer a string digitada (estamos assumindo que a expressão foi digitada corretamente com um espaço entre cada caracter) e avaliar cada caracter diferente de espaço.

Se for um número, basta empilhar este número (precisamos primeiro convertê-lo para número). Se for uma operação matemática, precisamos desempilhar dois números da pilha, realizar a operação matemática e empilhar novamente o resultado. Ao final a pilha terá um único valor que é o resultado da expressão.

Vamos simular estes passos para a segunda expressão: 5 3 2 + * 4 / 6 –
1) empilha o 5
2) empilha o 3
3) empilha o 2
4) desempilha dois valores (3 e 2), realiza a operação e insere na pilha o resultado. A pilha está assim: 5, 5
5) desempilha dois valores (5 e 5), realiza a operação e empilha o resultado. A pilha está assim: 25
6) empilha o 4
7) desempilha dois valores (25 e 4), realiza a operação e empilha o resultado. A pilha está assim: 6.25
8) empilha o 6
9) desempilha dois valores (6.25, 6), realiza a operação e empilha o resultado. A pilha está assim: 0.25
10) como a string terminou, o único valor da pilha é o resultado da expressão

Agora, vamos escrever este algoritmo usando a linguagem C.

Como estamos assumindo que cada elemento da expressão está separado por um espaço, podemos utilizar a função strtok para dividir nossa string em tokens. Se você não conhece essa função é porque pulou a aula 141.

Agora que conseguimos acessar diretamente cada caracter da expressão, precisamos verificar se é ou não uma operação matemática. Se não for uma operação matemática, significa que é um número, então vamos convertê-lo para número com a função strtol e inserir na pilha. Contudo, se for uma operação matemática, então desempilhamos dois valores , realizamos a operação e empilhamos novamente o resultado.

Para o nosso exemplo da segunda expressão, observe que 3 – 2 é diferente de 2 – 3. Ou seja, precisamos realizar a operação do segundo valor desempilhado com o primeiro, senão teremos valores incorretos. Lembre-se que o 2 está no topo da pilha, foi o última valor empilhado, logo será o primeiro valor desempilhado.

    pt = strtok(x, " ");
    while(pt){
        if(pt[0] == '+' || pt[0] == '-' || pt[0] == '/' || pt[0] == '*'){
            n1 = desempilhar(&pilha);
            n2 = desempilhar(&pilha);
            num = operacao(n2->valor, n1->valor, pt[0]);
            pilha = empilhar(pilha, num);
            free(n1);
            free(n2);
        }
        else{
            num = strtol(pt, NULL, 10);
            pilha = empilhar(pilha, num);
        }
        pt = strtok(NULL, " ");
    }

A seguir temos a função completa para resolver uma expressão em notação pós-fixa.

float resolver_expressao(char x[]){
    char *pt;
    float num;
    No *n1, *n2, *pilha = NULL;

    pt = strtok(x, " ");
    while(pt){
        if(pt[0] == '+' || pt[0] == '-' || pt[0] == '/' || pt[0] == '*'){
            n1 = desempilhar(&pilha);
            n2 = desempilhar(&pilha);
            num = operacao(n2->valor, n1->valor, pt[0]);
            pilha = empilhar(pilha, num);
            free(n1);
            free(n2);
        }
        else{
            num = strtol(pt, NULL, 10);
            pilha = empilhar(pilha, num);
        }
        pt = strtok(NULL, " ");
    }
    n1 = desempilhar(&pilha);
    num = n1->valor;
    free(n1);
    return num;
}

Observe que esta função não faz propriamente as operações, ela gerencia a estrutura pilha, empilhando e desempilhando. Para realizar as operações matemáticas temos outra função que recebe dois valores e uma operação a ser realizada, faz a operação e retorna o valor, como apresentado a seguir.

float operacao(float a, float b, char x){
    switch(x){
    case '+':
        return a + b;
        break;
    case '-':
        return a - b;
        break;
    case '/':
        return a / b;
        break;
    case '*':
        return a * b;
        break;
    default:
        return 0.0;
    }
}

Código completo em C para resolver uma expressão em notação pós-fixa (notação polonesa reversa)

/*      Aula 233

        4) Notação pós-fixa (polonesa reversa) (calculadoras HP)
        Infixa	                    Pós-fixa
        (51+13*12)                  51 13 12 * +                R = 207
        (5*(3+2)/4-6)               5 3 2 + * 4 / 6 -           R = 0,25
        (5+3+2*4-6*7*1)             5 3 + 2 4 * + 6 7 * 1 * -   R = -26
        (5*(3+(2*(4+(6*(7+1))))))   5 3 2 4 6 7 1 + * + * + *   R = 535

        Código escrito por Wagner Gaspar
        Julho de 2021
*/

typedef struct no{
    float valor;
    struct no *proximo;
}No;

No* empilhar(No *pilha, float num){
    No *novo = malloc(sizeof(No));

    if(novo){
        novo->valor = num;
        novo->proximo = pilha;
        return novo;
    }
    else
        printf("\tErro ao alocar memoria!\n");
    return NULL;
}

No* desempilhar(No **pilha){
    No *remover = NULL;

    if(*pilha){
        remover = *pilha;
        *pilha = remover->proximo;
    }
    else
        printf("\tPilha vazia\n");
    return remover;
}

float operacao(float a, float b, char x){
    switch(x){
    case '+':
        return a + b;
        break;
    case '-':
        return a - b;
        break;
    case '/':
        return a / b;
        break;
    case '*':
        return a * b;
        break;
    default:
        return 0.0;
    }
}

float resolver_expressao(char x[]){
    char *pt;
    float num;
    No *n1, *n2, *pilha = NULL;

    pt = strtok(x, " ");
    while(pt){
        if(pt[0] == '+' || pt[0] == '-' || pt[0] == '/' || pt[0] == '*'){
            n1 = desempilhar(&pilha);
            n2 = desempilhar(&pilha);
            num = operacao(n2->valor, n1->valor, pt[0]);
            pilha = empilhar(pilha, num);
            free(n1);
            free(n2);
        }
        else{
            num = strtol(pt, NULL, 10);
            pilha = empilhar(pilha, num);
        }
        pt = strtok(NULL, " ");
    }
    n1 = desempilhar(&pilha);
    num = n1->valor;
    free(n1);
    return num;
}

int main(){
    char exp[50] = {"5 3 2 4 6 7 1 + * + * + *"};

    printf("Resultado de %s:\t", exp);
    printf("%f\n", resolver_expressao(exp));
}

Deixe um comentário

3 × 2 =

Wagner Gaspar

Capixaba de São Gabriel da Palha, Espírito Santo. Bacharel em Ciência da Computação pela Universidade Federal do Amazonas e mestre em informática pela Universidade Federal do Espírito Santo.