本篇博客部分内容出自《2022数据结构考研复习指导》,仅作个人学习记录。


目录

  • 一、中序表达式转后序表达式的目的
  • 二、转换步骤
  • 三、isp和icp的含义
  • 四、具体例子
  • 五、转后序表达式实现代码
  • 六、后序表达式的计算方法
  • 七、计算后序表达式实现代码


一、中序表达式转后序表达式的目的

  表达式求值是程序设计设计语言编译中一个最基本的问题。中序表达式不仅要依赖运算符的优先级,还要处理括号。如果计算机直接计算中序表达式,会用到大量if-else语句判断数字,运算符以及括号的关系,非常复杂。
  后序表达式的运算符在操作数后面,在后序表达式中已经考虑了运算符的优先级,没有括号,只有操作数和运算符,无论多复杂的表达式都只需要一个栈进行运算。因此,后序表达式更适合被计算机运行。

二、转换步骤

从左往右开始扫描中序表达式;
遇到数字时,加入后序表达式;
遇到运算符时:

  • a.若为’(’,入栈;
  • b.若为’)’,则依次把栈中的运算符加入后序表达式,直到栈中出现’(’,从栈中删除’)’;
  • c.若为除括号外的其他运算符,当其优先级高于除‘(’外的栈顶运算符时,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,直到一个比它优先级低的或遇到一个左括号为止。
    当扫描的中序运算符结束时,栈中的所有运算符依次出栈加入后序表达式。

三、isp和icp的含义

  从上面可知,转换过程最难也是最重要的部分就是运算符的优先级的比较。接下来就讲解这部分。
  运算符的优先级如下表所示,其中isp(in stack priority)是栈内优先icp(in coming priority)是栈外优先

操作符

#

(

* , /

+ , -

}

isp

0

1

5

3

6

icp

0

6

4

2

1

 这个表是怎么的这里就不展开讨论了,感兴趣的读者可以看看这个博客:

icp和isp的含义是什么呢?
  由转换步骤的a可知,当遍历到中序表达式的一个运算符时,如果不是’(‘和’)’,需要比较中序表达式运算符的优先级的栈顶运算符的优先级,具体是:取中序表达式运算符的栈外优先级icp(因为中序表达式运算符是在栈外)与栈顶运算符的栈内优先级isp(因为栈顶运算符是在栈内)进行比较。

各个运算符的优先级如何理解?

  • ‘#’:这个符号代表中序表达式的开始与结束。当遍历到开头的’#’,直接放入栈内,因为’#‘的栈内优先级是最小的,所以对后面的运算符比较不会造成任何影响。当遍历到结尾的’#’,因为它的栈外优先级是最小的,所以会让栈里的运算符依次出栈输出然后结束。
  • ‘(’和’)’:在中序表达式中,我们要优先计算括号里的内容,括号里面是优先级最高的而在后续表达式中,要如何做到这个特性呢?首先对于’(’,当’(‘为栈外运算符时,它的优先级最高,所以可以直接入栈。入栈后优先级变成除了’#‘之外最低;对于’)’,当’)‘为栈外运算符时,它的优先级是除了’#'最低的,这是为了把括号里面运算符都出栈并输出,以保证括号里的内容先进行运算。
  • ‘+ , -’:在中序表达式中,我们要先计算’*,/‘再计算’+,-’,而这就要使’+,-‘的栈内和栈外的优先级都比’*,/‘的栈内优先级低,这是因为一旦遍历到’+,-’,就可以让栈里的’*,/‘出栈并输出,再让’+,-‘入栈,以达到先计算’*,/‘再计算’+,-‘的目的。而’+,-‘的栈内优先级比栈外优先级高是因为如果连续遇到两个’+,-‘的运算符时,我们应该从左到右运算,即先算栈内的,再算栈外的,’+,-'的栈内优先级比栈外优先级高
  • ‘* , /’:和’+,-'的原理相似。

四、具体例子

将中序表达式#a+b-a*((c+d)/e-f)+g#转换成后序表达式

  1. #,#直接进栈。
    栈内内容:’#’
    输出:’’
  2. a,a为操作数,直接输出。
    栈内内容:’#’
    输出:‘a’
  3. +,因为isp(#)<icp(+),将+入栈。
    栈内内容:’#+’
    输出:‘a’
  4. b,b为操作数,直接输出。
    栈内内容:’#+’
    输出:‘ab’
  5. -,因为isp(+)>icp(-),所以+出栈并输出;因为isp(#)<icp(-),所以-入栈。
    栈内内容:’#-’
    输出:‘ab+’
  6. a,a为操作数,直接输出。
    栈内内容:’#-’
    输出:‘ab+a’
  7. *,因为isp(-)<icp(*),所以将*入栈。
    栈内内容:’#-*’
    输出:‘ab+a’
  8. (,因为isp(*)<icp()),所以(入栈。
    栈内内容:’#-*(’
    输出:‘ab+a’
  9. (,因为isp(()<icp()),所以(入栈。
    栈内内容:’#-*((’
    输出:‘ab+a’
  10. c,c是操作数,直接输出。
    栈内内容:’#-*((’
    输出:‘ab+ac’
  11. +, 因为isp(()<icp(+),所以+进栈。
    栈内内容:’#-*((+’
    输出:‘ab+ac’
  12. .d,d是操作数,直接输出。
    栈内内容:’#-*((+’
    输出:‘ab+acd’
  13. ),isp(+)>icp()),所以+出栈并输出;因为isp(()==icp()),所以(出栈。
    栈内内容:’#-*(’
    输出:‘ab+acd+’
  14. /,因为isp(()<icp(/),所以/进栈。
    栈内内容:’#-*(/’
    输出:‘ab+acd+’
  15. e,e为操作数,直接输出。
    栈内内容:’#-*(/’
    输出:‘ab+acd+e’
  16. -,因为isp(/)>icp(-),所以/出栈并输出;因为isp(()<icp(-),所以-入栈。
    栈内内容:’#-*(-’
    输出:‘ab+acd+e/’
  17. f,f为操作数,直接输出。
    栈内内容:’#-*(-’
    输出:‘ab+acd+e/f’
  18. ),isp(-)>icp()),所以-出栈并输出;因为isp(()==icp()),所以(出栈。
    栈内内容:’#-*’
    输出:‘ab+acd+e/-’
  19. +,isp(*)>icp(+),所以*出栈并输出;因为isp(-)==icp(+),所以-出栈并输出;因为isp(#)<icp(+),所以+入栈。
    栈内内容:’#+’
    输出:‘ab+acd+e/f-*-’
  20. g,g为操作数,直接输出。
    栈内内容:’#+’
    输出:‘ab+acd+e/f-*-g’
  21. #,因为isp(+)>icp(#),所以+出栈并输出;因为isp(#)==icp(#),所以#出栈并结束。
    栈内内容:’’
    输出:‘ab+acd+e/f-*-g+’

五、转后序表达式实现代码

#include <iostream>
#include<map>
#include <cstring>
using namespace std;
#define MaxSize 50

typedef struct {
    char data[MaxSize];
    int top;
}SqStack;

//初始栈
void InitStack(SqStack &S) {
    S.top = -1;
}

//入栈
bool Push(SqStack &S, char x) {
    if (S.top == MaxSize - 1)
        return false;
    S.data[++S.top] = x;
    return true;
}

//出栈
bool Pop(SqStack& S, char &x) {
    if (S.top == -1)
        return false;
    x = S.data[S.top--];
    return true;
}

//查看栈顶元素
bool GetPop(SqStack S, char& x) {
    if (S.top == -1)
        return false;
    x = S.data[S.top];
    return true;
}


int main()
{   
    map<char, int> isp;
    map<char, int> icp;
    isp = {{ '#', 0},{ '(', 1},{ '*', 5},{ '/', 5},{ '+', 3},{ '-', 3},{ '-', 6}};
    icp = {{ '#', 0},{ '(', 6},{ '*', 4},{ '/', 4},{ '+', 2},{ '-', 2},{ '-', 1}};
    string expression1 = "#a+b-a*((c+d)/e-f)+g#";  //中序表达式
    string expression2 = "";  //后序表达式
    SqStack S;
    InitStack(S);
    for (int i = 0; i < expression1.length(); i++) {
        //如果是数字,直接加入后序表达式
        if (expression1[i] >= 'a' && expression1[i] <= 'z'){
            expression2 = expression2 + expression1[i];
        }
        //如果是'('直接加入后序表达式
        if (expression1[i] == '(')
            Push(S, expression1[i]);
        //如果是')'
        if(expression1[i] == ')')
            for (int j=S.top; j>=0 ; j--){
                char temp;
                GetPop(S, temp);
                if (temp != '('){
                    Pop(S, temp);
                    expression2 = expression2 + temp;
                }
                else{
                    Pop(S, temp);
                    break;
                }
            }
        //如果是'#'
        if (expression1[i] == '#')
            if(i==0)
                Push(S, expression1[i]);
            else
                for (int j = S.top; j >= 0; j--){
                    char temp;
                    GetPop(S, temp);
                    if (temp != '#'){
                        Pop(S, temp);
                        expression2 = expression2 + temp;
                    }
                    else{
                        Pop(S, temp);
                        break;
                    }
                }

        if(expression1[i]=='*' || expression1[i]=='/' || expression1[i] == '+' || expression1[i] == '-')
            for (int j = S.top; j >= 0; j--){
                char temp;
                GetPop(S, temp);
                if (isp[temp]<icp[expression1[i]]){
                    Push(S, expression1[i]);
                    break;
                }
                else{
                    Pop(S, temp);
                    expression2 = expression2 + temp;
                }
            }     
    }
    cout << "中序表达式:" << expression1 << endl;
    cout << "后序表达式:" << expression2 << endl;
}

六、后序表达式的计算方法

扫描后序表达式的每一项,根据它的类型做如下相应操作:

  • 若该项为操作数,则将其压入栈中。
  • 若该项是操作符<op>,则连续从栈中推出两个操作数Y和X,形成运算指令X<op>Y,并将计算结果重新压入栈中。

当后序表达式的所有项都扫描并处理完成后,栈顶存放的就是最后的计算结果。

七、计算后序表达式实现代码

#include <iostream>
using namespace std;
#define MaxSize 50

typedef struct {
    char data[MaxSize];
    int top;
}SqStack;

//初始栈
void InitStack(SqStack& S) {
    S.top = -1;
}

//入栈
bool Push(SqStack& S, char x) {
    if (S.top == MaxSize - 1)
        return false;
    S.data[++S.top] = x;
    return true;
}

//出栈
bool Pop(SqStack& S, char& x) {
    if (S.top == -1)
        return false;
    x = S.data[S.top--];
    return true;
}

//查看栈顶元素
bool GetPop(SqStack S, char& x) {
    if (S.top == -1)
        return false;
    x = S.data[S.top];
    return true;
}

int main()
{
    SqStack S;
    InitStack(S);
    string expression = "326+*";  //后序表达式 中序表达式的形式为3*(2+6)
    for (int i = 0; i < expression.length(); i++){
        if (expression[i] >= '0' && expression[i] <= '9')
            Push(S, expression[i]);
        else {
            int Y, X;
            char temp;
            Pop(S, temp);
            Y = int(temp) - 48;  //将char类型数字传换成int类型数字
            Pop(S, temp);
            X = int(temp) - 48;
            cout << X << " " << Y<<endl;
            if (expression[i] == '+')
                Push(S, char(X + Y + 48));  将int类型数字传换成char类型数字再入栈
            else if(expression[i] == '-')
                Push(S, char(X - Y + 48));
            else if (expression[i] == '*')
                Push(S, char(X * Y + 48));
            else if (expression[i] == '/')
                Push(S, char(X / Y + 48));
        }
    }
    int result;
    char temp;
    Pop(S, temp);
    result = int(temp) - 48;
    cout << "后续表达式:" << expression << endl;
    cout << "结果为:" << result << endl
}