zoukankan      html  css  js  c++  java
  • 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

    ------------ 转载请注明出处 ------------
  • 相关阅读:
    替换指定串函数
    实现超级链接
    面向对象的关系数据库设计
    SQL语句的添加、删除、修改多种方法
    InfoWorld2008最佳开源软件大奖
    判断字符是否是汉字
    delphi指针
    项目经理要“三心二意”
    Linq查询Specified cast is not valid异常的常见原因
    SQL SERVER数据库同步示例
  • 原文地址:https://www.cnblogs.com/whlook/p/7143327.html
Copyright © 2011-2022 走看看