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

前面既然写了中缀转后缀的,那么现在说下中缀转前缀的,至于后缀(前缀)转中缀,可以根据相关的转换规则自行转换。

目的

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

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

转换原则:

与中缀转后缀不同,前者是顺序从左到右读取每一个字符,后者是从右到左顺序读取每一个字符,然后进行反转字符串。

  1. 如果遇到操作数,直接将操作数放入到prefix 中
  2. 如果遇到操作符,如果符号栈为空,直接放入符号栈中,如果符号栈不为空,则判断当前栈顶元素 
    • 如果当前栈顶元素为右括号‘)’,直接将操作符放入符号栈中
    • 如果当前栈顶元素的优先级大于操作数的优先级,则将栈顶元素移除,再次和判断移除后栈的栈顶元素比较优先级大小,直到当前栈顶元素小于或等于操作数优先级,将操作符放入符号栈中
  3. 如果遇到右括号,直接将右括号放入符号栈中
  4. 如果遇到左括号,将右括号到左括号之间的全部符号移出到prefix 中(记得左括号不要入栈,并且在最后将右括号从栈中删除)
  5. 重复1-4,直到最后一个字符被读入。
  6. 判断当前栈是否为空,如果不为空,将栈中的元素依次移出到prefix 中
  7. 翻转字符串

和中缀转后缀不同,进行优先级比较的时候,需要注意等号的问题

实例

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

接下来读入‘6’,并送到输出,然后读入‘+’此时状态如下: 
栈:* ) + 
输出:7 6

然后读入‘5’,并送到输出,然后继续读入‘*’,由于‘*’的优先级比‘+’高,所以直接加入栈中,再将‘4’送到输出,因此状态如下: 
栈:* ) + * 
输出:7 6 5 4

下一个读入的符号‘(’,由于规则4,因此将符号栈中的操作符依次出栈,然后读入‘4’,并在最后将右括号弹出: 
栈:* 
输出: 7 6 5 4 * +

继续读入,此时读入‘+’,由优先级小于栈中‘*’的优先级,因此依照规则2,依次出栈,最后将‘+’入栈,接下来读入‘3’: 
栈:+ 
输出:7 6 5 4 * + * 3

往后读入的符号是‘*’,将‘*’入栈。然后将‘2’放入输出: 
栈:+ * 
输出:7 6 5 4 * + * 3 2

现在读入‘+’,由于符号栈中存在‘+’且它们的优先级相同,根据规则,除非,优先级大于栈顶元素,否则不出栈,依次栈中状态如下: 
栈:+ + 
输出:7 6 5 4 * + * 3 2 *

下一个读入‘1’: 
栈:+ + 
输出:7 6 5 4 * + * 3 2 * 1

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

最后翻转 
输出:+ + 1 * 2 3 * + * 4 5 6 7

实现代码

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

    infix(中缀表达式) : 1+2*3+(4*5+6)*7
    prefix(前缀表达式) : ++1*23*+*4567
*/
#include <algorithm>
#include <iostream>
#include <stack>
#include <string>
#include <map>
using namespace std;

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

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

    int infix_length = infix.size();            // 中缀表达式的字符长度
    prefix.reserve(infix_length);               // 提高效率
    for(int i = infix_length - 1; i >= 0; --i) {
        switch(infix[i]) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                prefix.push_back(infix[i]);
                break;
            case '+':
            case '-':
            case '*':
            case '/':
                if(!mark.empty()) {
                    char markTop = mark.top();
                    // 注意此处,与中缀转后缀有所不同
                    while(markTop != ')' && priority[infix[i]] < priority[markTop]) {
                        prefix.push_back(markTop);
                        mark.pop();
                        if(mark.empty()) {
                            break;
                        }
                        markTop = mark.top();
                    }
                }
                mark.push(infix[i]);
                break;
            case ')':
                mark.push(infix[i]);
                break;
            case '(':
            {
                char markTop = mark.top();
                while(markTop != ')') {
                    prefix.push_back(markTop);
                    mark.pop();
                    markTop = mark.top();
                }
                mark.pop();
            }
                break;
        }
    }
    // 剩余的全部出栈
    while(!mark.empty()) {
        prefix.push_back(mark.top());
        mark.pop();
    }
    reverse(prefix.begin(), prefix.end());
}

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

    cout << "infix : " << infix << endl;
    InfixToPrefix(infix, prefix);
    cout << "prefix : " << prefix << endl; 

    return 0;
}

猜你喜欢

转载自blog.csdn.net/momo_mo520/article/details/80855855
今日推荐