C++:后缀表达式

1.基本概念

后缀表示法也叫逆波兰表示法(前缀就是波兰表示法),由于所有的操作符都在操作数的后面,所以被称为后缀表示法。

中缀表示法的操作符在操作数之间,也是最符合人的逻辑。前缀表示法的操作符在操作数之前,它和后缀表示法一样,都是为了方便计算机计算,因为在后缀或前缀中没有括号,也不存在优先级处理的问题,直接利用栈进行计算。

示例:

中缀:5+(1+2)*4-3
后缀:512+4*+3-

2.中缀表示转后缀表示

中缀转后缀可以从左向右扫描表达式,然后按照规则进行处理,
对于中缀表达式a+(b+c)*d-e的转换步骤:

(1). 首先初始化两个栈:输出栈rpn_和操作符栈rpn_stack

(2). 从左至右扫描表达式,遇到操作数则直接压入输出栈,在遇到a时,由于是操作数,将"a"压入rpn_

(3). 继续扫描,遇到操作符时,如果该操作符优先级高于rpn_stack栈顶的操作符,则直接压入rpn_stack,如果同级或低于栈顶操作符,则将栈中操作符依次弹出(同时压入输出栈)直到遇到比当前操作符优先级低的(或者遇到了"("),然后压入操作符。(注意,对于操作符"(",只有")"才能将其弹出,其他情况不弹出"(")。现在我们扫描到了"+",由于当前的操作符栈空,直接压入。

(4). 然后读取到"(",由于它的优先级是最高的,只要遇到就直接压入栈。

(5). 然后读取到操作数"b",压入输出栈 rpn_。

(6). 继续读取到 "+" ,当前操作符栈的栈顶是"(",因为只有")"才能将其弹出,所以"+"入栈。

(7). 读取的"c"压入输出栈。

(8). 读取到了")",此时开始将操作符栈的操作符依次弹出(同时压入输出栈),直到遇到第一个"(",将"("弹出。("("和")"都不能进入输出栈)

(9). 然后读取到" * ",当前操作符栈的栈顶是"+",优先级低于" * ",所以直接压入栈。

(10). 读取的"d"压入输出栈

(11). 读取到"-",当前栈顶是" * ",比"-"的优先级高,所以" * "弹出(同时压入输出栈,下同),然后栈顶"+"的优先级和"-"相同,也要弹出。此时操作符栈空,"-"压入

(12). 读取到了"e",压入输出栈,此时表达式读取完毕,将操作符栈依次弹出并压入输出栈,完成了转换,输出为abc+d*+e-

以下是将中缀表达式转化为后缀表达式的代码:

// 比较操作符A和操作符B的优先级
bool opAisBiggerThanOpB(string opA, string opB)
{
    if (opA == "*" || opA == "/" && opB != "*" && opB != "/" && opB!= "(")
        return true;
    else
        return false;
}

// 中缀表达式转后缀表达式
bool parseFormula(string formula)
{
    vector<string> rpn_; // 总输出
    vector<string> rpn_stack; // 符号堆栈
    string sign_; // 临时保存操作数
    for (int i = 0; i < formula.size(); ++i)
    {
        if (formula[i] != '+'&&formula[i] != '-'&&formula[i] != '*'&&formula[i] != '/' && formula[i] != '(' &&formula[i] != ')') // 如果是操作数的话就保存起来等待输出
        {
            sign_ += formula[i];
        }
        else
        {
            string t_formula;
            t_formula += formula[i];

            // 操作数输出
            if (!sign_.empty()) 
            {
                    rpn_.push_back(sign_);
                    sign_.clear(); // 清空,保存下一个操作数
            }

            //操作符入栈
            if (t_formula == ")")
            {
                while (rpn_stack[rpn_stack.size() - 1] != "(")
                {
                    if (rpn_stack.empty())
                        return false;
                    rpn_.push_back(rpn_stack[rpn_stack.size() - 1]);
                    rpn_stack.pop_back();
                }
                rpn_stack.pop_back();

            }
            else if (rpn_stack.empty())
                rpn_stack.push_back(t_formula);
            else if (t_formula == "(" || rpn_stack[rpn_stack.size() - 1] == "(")
                rpn_stack.push_back(t_formula);
            else if (opAisBiggerThanOpB(t_formula, rpn_stack[rpn_stack.size() - 1]))
                rpn_stack.push_back(t_formula);
            else 
            {
                while (!opAisBiggerThanOpB(t_formula, rpn_stack[rpn_stack.size() - 1]) && rpn_stack[rpn_stack.size() - 1]!="(")
                {

                    rpn_.push_back(rpn_stack[rpn_stack.size() - 1]);
                    rpn_stack.pop_back();
                    if (rpn_stack.empty())
                        break;
                }
                rpn_stack.push_back(t_formula);
            }




        } // end else
    } // end for

    // 处理最后的还留在暂存区的操作数和操作符
    if (!sign_.empty())
        rpn_.push_back(sign_);
    if(!rpn_stack.empty())      
    {
        for(int i = rpn_stack.size()-1;i>=0;--i)
            rpn_.push_back(rpn_stack[i]);
    }

    // 输出测试
    string rpn;
    for (int i = 0; i < rpn_.size(); ++i)
    {
        rpn += rpn_[i];
    }
    cout << rpn << endl; 

    return true;
}

例如:parseFormula("5+((1+2)*4)-3");

输出为:512+4*+3-

3.后缀表达式的计算

对于后缀表达式:5 1 2 + 4 * + 3 -

(1). 首先建立一个栈 res 用来保存中间值,从左到右读取后缀表达式,遇到操作数直接入栈,遇到操作符则将栈顶的两个操作数弹出,完成计算后将计算结果压入栈。

(2). 首先读取了 5、1、2,将它们依次入栈,当前的栈:

res: 栈底 5 1 2 栈顶

(3). 然后读取到操作符"+",弹出2,然后弹出1,将1+2的运算结果3压入栈:

res: 栈底 5 3 栈顶

(4). 然后读取到的操作数"4"入栈,接着读取到" * ",如同上面,将4弹出,将3弹出,计算3*4然后将12压入栈。

(5). 后面的操作和前面一样。

(6). 结果:14

转载于:https://www.cnblogs.com/whlook/p/7143327.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值