天天看点

表达式转换

算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。

输入格式:

输入在一行中给出不含空格的中缀表达式,可包含

+

-

*

\

以及左右括号

()

,表达式不超过20个字符。

输出格式:

在一行中输出转换后的后缀表达式,要求不同对象(运算数、运算符号)之间以空格分隔,但结尾不得有多余空格。

输入样例:

2+3*(7-4)+8/4
           

输出样例:

2 3 7 4 - * + 8 4 / +
           

Note:这一题比较注重细节方面的考察,有一些很容易忽视的点都要考虑到,具体是什么且听我娓娓道来。

首先,中缀表达式怎么转换为后缀表达式,两个栈,一个运算符栈,一个输出栈,进输出栈就相当于输出了:

逐个字符的读取输入的表达式

(1)读到左括号“(”,直接存入运算符栈。

(2)读到右括号“)”,将运算符栈中“(”前的所有运算符弹入输出栈。

(3)读到其他运算符,将该运算符和运算符栈栈顶运算符作比较:若其优先级高于栈顶运算符优先级,则直接存入运算符栈,

否则将栈顶运算符弹入输出栈,如此循环直到栈顶运算符的优先级小于读到的运算符为止,再压入运算符栈。

(4)读取完表达式后,运算符栈中还有运算符时,则将所有运算符弹入输出栈。

过程很简单,为了方便,我分别用ABCD表示“-”,“+”,“*”,“/”的,优先级从小到大,这样在判断优先级时可直接根据字符ABCD的ASCII码值大小来比较。好,现在我来细讲其中需要注意的细节。为什么要注意这些细节,因为我们做题AC是一个目的,同时能设计出更具通用性的算法是更高层次的目的。当题目约束条件变多时,你的算法是否能够适应也是一项考验,而不是单纯地为了AC而写出能AC的代码。

(1)正负号:你的算法要能正确判断出正负号,正号如何处理?负号如何处理?结合数学知识想一下。比如2+(+5)。

(2)空格:题目对输出格式有明显的要求,你该怎么设计这块的输出?哪些地方需要输出空格?

(3)小数:遇到小数该怎么处理?遇到指数科学计数法呢?最好的办法就是当

(4)比较:在将运算符栈元素弹入输入栈时,仅仅直到优先级更小就停止吗?还有限制条件吗?

#include <stdio.h>
#include <string.h>

char stack[50], str[50], post[50]; // 符号栈,表达式字符串,输出栈
int top1 = -1, top2 = -1;

char Pop( char c )
{
    if (c == 'D') return '/';
    if (c == 'C') return '*';
    if (c == 'B') return '+';
    if (c == 'A') return '-';
}

void Compare( char c ) // 传入字符来比较优先级进而对stack执行相应的操作
{
    if (c == ')') // 如果遇到右括号
    {
        while (stack[top1] != '(' && top1 != -1) // 一直出栈直到遇到第一个左括号或栈空
        {
            post[++top2] = Pop(stack[top1]); // 弹出到输出栈
            post[++top2] = ' ';
            stack[top1--] = '\0'; // 栈顶下移
        }
        stack[top1--] = '\0'; // 此时stack[top1]为左括号,直接弹出即可
    }
    else // 如果是其他的操作符
    {
        while (stack[top1] >= c && stack[top1] != '(' && top1 != -1) // 一直出栈直到遇到优先级更小或者左括号或栈空
        {
            post[++top2] = Pop(stack[top1]); // 弹出到输出栈
            post[++top2] = ' ';
            stack[top1--] = '\0'; // 栈顶下移
        }
        stack[++top1] = c;
    }
}

int main(void)
{
    scanf("%s", str);
    for (int i = 0; str[i] != '\0'; i++)
    {
        if (str[i] == '(')
            stack[++top1] = str[i]; // 左括号直接入栈
        else if (str[i] == '-' && (i == 0 || str[i - 1] == '(')) // 负号进入输出栈
            post[++top2] = str[i];
        else if (str[i] == '+' && (i == 0 || str[i - 1] == '(')) // 遇到正号直接跳过
            continue;
        else if (str[i] == '-' && i !=0 && str[i - 1] != '(') // 减号
            Compare('A');
        else if (str[i] == '+' && i != 0 && str[i - 1] != '(') // 加号
            Compare('B');
        else if (str[i] == '*') // 乘号
            Compare('C');
        else if (str[i] == '/') // 除号
            Compare('D');
        else if (str[i] == ')') // 右括号
            Compare(')');
        else
        { // 对待运算符外的字符,最好的方法是一视同仁,只在运算符上进行限制
            post[++top2] = str[i];
            if (str[i + 1] == '+' || str[i + 1] == '-' || str[i + 1] == '*'
                || str[i + 1] == '/' || str[i + 1] == '(' || str[i + 1] == ')' || str[i + 1] == '\0')
                post[++top2] = ' '; // 输出一位空格
        }
    }

    while (top1 != -1) // 栈中剩余运算符全部输出
    {
        post[++top2] = Pop(stack[top1--]);
        post[++top2] = ' ';
    }
    if (post[top2] == ' ')
        post[top2--] = '\0'; // 如果结尾是多余空格则删除掉
    printf("%s", post);

    return 0;
}
           

自己试着不要看把代码码出来哦,测试样例可以直接复制,加油小伙汁小改改,为了更美好的未来呢~~~