利用栈实现中缀表达式转后缀表达式

简介

中缀表示法(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)。与前缀表达式(例:+ 3 4)或后缀表达式(例:3 4 +)相比,中缀表达式不容易被电脑解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。

逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。

目的

将中缀表达式(即标准的表达式)转换为后缀表达式

例如:1+2*3+(4*5+6)*7 转换成 123*+45*6+7*+

转换原则:

  1. 当读到一个操作数时,立即将它放到输出中。操作符不立即输出,放入栈中。遇到圆括号也是推入栈中。

  2. 如果遇到一个右括号,那么就将栈元素弹出,将符号写出直到遇到一个对应的左括号。但是这个左括号只被弹出,并不输出。

  3. 在读到操作符时,如果此时栈顶操作符优先级大于或等于此操作符,弹出栈顶操作符直到发现优先级更低的元素位置。除了处理‘)’的时候,否则决不从栈中移走‘(’。操作符中,‘+’和‘-’优先级最低,‘*’和‘/’优先级中等,‘(’和‘)’最高。

  4. 如果读到输入的末尾,将栈元素弹出直到该栈为空,将符号写到输出中。

实例

首先,读入‘1’,并送到输出,然后‘+’被读入并压入栈中。接下来‘2’读入并送到输出,此时状态如下: 
栈:+ 
输出:1 2

接下来读入‘*’,由于优先级比栈顶元素‘+’大(原则3),因此被压入栈中,接着读入‘3’,并送到输出: 
栈:+ * 
输出:1 2 3

然后读入‘+’,由于此时栈顶元素为‘*’,优先级比‘+’大,因此将‘*’弹出,弹出后原来的‘+’变为栈顶元素,由于‘+’的优先级和当前读入的‘+’优先级相等,因此也被弹出(原则3),最后将读入的‘+’压入栈中,因此状态如下: 
栈:+ 
输出:1 2 3 * +

下一个读入的符号‘(’,由于具有最高优先级,因此将其放入栈中,然后读入‘4’: 
栈:+ ( 
输出: 1 2 3 * + 4

继续读入,此时读入‘*’,除非处理‘)’,否则‘(’绝不会弹出,因此‘*’被压入栈中,接下来读入‘5’: 
栈:+ (* 
输出:1 2 3 * + 4 5

往后读入的符号是‘+’,将‘*’弹出并输出。然后将‘+’压入栈中,接着读入‘6’: 
栈:+ ( + 
输出:1 2 3 * + 4 5 * 6

现在读入‘)’,因此弹出栈中元素直到遇到‘(’: 
栈:+ 
输出:1 2 3 * + 4 5 * 6 +

下一个有读入‘*’,被压入栈中,然后读入‘7’: 
栈:+ * 
输出:1 2 3 * + 4 5 * 6 + 7

现在输入为空,弹出所有栈中元素 
栈:空 
输出:1 2 3 * + 4 5 * 6 + 7 * +

实现代码

/*
    利用栈将(中缀表达式)转换成(后缀表达式)
    e.g.
        1+2*3+(4*5+6)*7 转换成 123*+45*6+7*+

    infix(中缀表达式) : 1+2*3+(4*5+6)*7
    postfix(后缀表达式) : 123*+45*6+7*+
*/
#include <iostream>
#include <string>
#include <stack>
#include <map>
using namespace std;

void InfixToPostfix(const string infix, string& postfix)
{
    stack<char> mark;                       // 符号栈

    std::map<char, int> priority;               // 符号优先级
    priority['+'] = 0;
    priority['-'] = 0;
    priority['*'] = 1;
    priority['/'] = 1;

    int infix_length = infix.size();            // 中缀表达式的字符长度
    postfix.reserve(infix_length);              
    for(int i = 0; i < infix_length; ++i) {
        switch(infix[i]) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            postfix.push_back(infix[i]);
            break;
        case '+':
        case '-':
        case '*':
        case '/':
            if(!mark.empty()) {
                char markTop = mark.top();
                while(markTop != '(' && priority[infix[i]] <= priority[markTop]) {
                    postfix.push_back(markTop);
                    mark.pop();
                    if(mark.empty()) {
                        break;
                    }
                    markTop = mark.top();
                }
            }
            mark.push(infix[i]);
            break;
        case '(':
            if(infix[i - 1] >= '0' && infix[i - 1] <= '9') {    // 5(6/2-1) <==> 5*(6/2-1)
                mark.push('*');
            }
            mark.push(infix[i]);
            break;
        case ')':
        {
            char markTop = mark.top();
            while(markTop != '(') {
                postfix.push_back(markTop);
                mark.pop();
                markTop = mark.top();
            }
            mark.pop();
        }
            break;
        default:
            break;
        }
    }

    // 剩余的全部出栈
    while(!mark.empty()) {
        postfix.push_back(mark.top());
        mark.pop();
    }
}

int main(int argc, char const *argv[])
{
    std::string infix = "1+2*3+(4*5+6)*7+(1+2)";
    std::string postfix;

    cout << "infix : " << infix << endl;
    InfixToPostfix(infix, postfix);
    cout << "postfix : " << postfix << endl; 

    return 0;
}

猜你喜欢

转载自blog.csdn.net/momo_mo520/article/details/80855875