Algoritmo de Shunting-Yard

Um algoritmo que transforma expressões matemáticas infixas em posfixas.

Motivação

Expressão infixa

Expressão posfixa

A*2

A2*

(A*2+c-d)/2

A2*c+d-2/

(2*4/a^b)/(2*c)

24*ab^/2c*/

A tarefa de transformar expressões matemáticas infixas para posfixas é bastante útil por dar um formato mais fácil ao computador para calcular as expressões da forma como escrevemos, removendo algumas das ambiguidades que suscetivelmente escrevemos. Repare que na forma posfixa sempre temos primeiro os operandos e depois o operador, fazendo com que o cálculo seja muito mais simples, num processo onde se vai acumulando os operandos numa pilha e toda vez que ler um operador, retirar os dois operandos que estão mais no topo, fazer a conta e retornar o resultado para o topo da pilha, assim sucessivamente até que se acabe a expressão e o resultado esteja no topo da pilha restante.

Para a explicação deste algoritmo, vamos considerar quatro tipos diferentes de símbolos possíveis na nossa expressão matemática:

  • Operandos: representados na entrada como caracteres alfanuméricos

  • Operadores: representados na entrada como os caracteres +, -, *, / e ^

  • Parênteses aberto: representando o começo de uma subexpressão

  • Parênteses fechado: representando o final de uma subespressão

Também vamos precisar considerar a precedência dos operadores, ou seja, a ordem em que precisamos fazer as contas. A fim de permanecer em caráter computacional, vamos entender precedência como números, onde um número maior significa maior precedência.

Operador

Precedência

+

1

-

1

*

2

/

2

^

3

Para traduzirmos corretamente a expressão infixa para posfixa, o algoritmo utiliza uma pilha para guardar os operadores e os parênteses à medida que formos lendo cada um deles. Com isso, vamos lendo a expressão um caractere por vez, tomando medidas diferentes dependendo de qual caractere estamos lendo no momento:

  • Se o caractere é um operando, escrever tal caractere direto na resposta

  • Se o caractere é um parênteses aberto, colocar um parênteses aberto na pilha

  • Se o caractere é um parênteses fechado, ir tirando operadores da pilha, escrevendo-os na resposta, até encontrarmos um parênteses aberto na pilha, caso em que vamos retirá-lo da pilha, mas não vamos escrevê-lo na resposta

  • Se o caractere é um operador, ir tirando operadores da pilha, escrevendo-os na resposta, até uma dessas três possibilidades acontecer. Quando algo abaixo acontecer, coloque o operador na pilha e passe para o próximo caractere.

    • A pilha estar vazia

    • Encontrarmos um parênteses aberto

    • Encontrarmos um operador com precedência menor do que a do operador que lemos naquele momento

      • Seria inteligente aqui separarmos o caso em que lemos ^ para ir direto colocar na pilha, já que qualquer operador que encontrássemos na pilha teria precedência menor que ^

Implementação

Para as implementações de pilha usadas neste algoritmo, confira nossa página de pilhas.

int precedencia(char operador){
    switch(operador){
        case '+':
        case '-':   return 1;
        case '*':
        case '/':   return 2;
    }
}

struct pilha p;
char expressao[301];

inicializa(&p);

tam = strlen(expressao);
for(int i = 0; i < strlen(expressao); ++i){
    if(isalpha(expressao[i]) || isdigit(expressao[i])){
        printf("%c", expressao[i]);
    }else if(expressao[i] == '(' || expressao[i] == '^'){
        push(&p, expressao[i]);
    }else if(expressao[i] == ')'){
        while(!empty(&p) && top(&p) != '('){
            printf("%c", top(&p));
            pop(&p);
        }

        if(!empty(&p))  pop(&p);
    }else{
        while(!empty(&p) && top(&p) != '(' && precedencia(expressao[i]) <= precedencia(top(&p))){
            printf("%c", top(&p));
            pop(&p);
        }

        push(&p, expressao[i]);
    }
}

while(!empty(&p)){
    printf("%c", top(&p));
    pop(&p);
}
printf("\n");

Problemas

1077 - Infixa para Posfixa

Last updated

Was this helpful?