C++ Primer 第五版 练习9.52 解答

练习9.52:使用stack处理括号化的表达式。当你看到一个左括号,将其记录下来。当你在一个左括号之后看到一个右括号,从stack中pop对象,直至遇到右括号,将左括号也一起弹出栈。让后将一个值(括号内的运算结果)push到栈中,表示一个括号化的(子)表达式已经处理完毕,被其运算结果所替代。


说实话:看见题目,第一回读没有读懂,读了几回之后,脑中忽然想起了大二还是大三刘sir(数据结构老师)讲的二叉树的中序遍历那块,为什么会想到那儿,说不清楚,然后自然联想到中缀表达式,去度娘了一下了,题目的意思明白了,其实概括来说就是中缀表达式的求值,对于以前就没好好听的数据结构课,忽然觉得这道题将是一个难缠的主,果然,接下来的一天过,再没有度娘的情况下,尝试去写这个程序,结果彻底郁闷了,想想功力还没到,还需要多练,最后还是去度了,看了一篇不错的博文,作者 海子,参考网址

http://www.cnblogs.com/dolphin0520/p/3708602.html


然后,看了别人的东西,自己就模仿着写了一遍,最后整理了下中缀表达式 的求值过程,以供参考

/*

*说明:中缀表达式求值函数说明

1.扫描表达式

  a.如果 token 是 "+","-","*","/"

    a1.符号栈为空,token直接入栈

          a2.符号栈不空,比较token和栈顶符号的优先级

             如果token的优先级高,直接入栈

                   否则将栈里面的符号出栈,并和数字栈进行计算,设置新的栈顶符号和优先级,一直到优先级低的全部弹出栈,循环停止,新的符号入栈

  b.如果 token是 "(",直接入栈

  c. 如果token是")"

         当stack_opt.top !="(",既没有找到最近的和右括号匹配的左括号

                     操作符弹出栈,并和操作数计算

                     最后将"("也弹出去

                     ”)“不进栈,它的作用是为了消除掉最近的左括号) //循环外的pop是将左括号丢弃

  d.剩下的情况就都是数字,直接进入操作数栈

*/

 

我相信大家的功力都比我要好,因此,我还要继续努力,贴上自己写的代码,尽管基本就是照着原作者的依葫芦画瓢了一下,但还是有受益的,附上代码

/*
*练习9.52 
*2015/8/9
*问题描述: 练习9.52:使用stack处理括号化的表达式。当你看到一个左括号,将其记录下来。当你在一个左括号之后看到一个右括号,从stack中pop对象,直至遇到右括号,将左括号也一起弹出栈。让后将一个值(括号内的运算结果)push到栈中,表示一个括号化的(子)表达式已经处理完毕,被其运算结果所替代。 
*说明:自己模仿网上的写了一遍,熟悉了中缀 表达式计算的流程
*作者:NickFeng 
*邮箱:NickGreen23@163.com
*/ 

/*
*说明:
1.扫描表达式
  a.如果 token 是 "+" ,"-","*","/"
     a1.符号栈为空,直接入栈
	 a2.符号栈不空,比较token和栈顶符号的优先级
	    如果token的优先级高,直接入栈
		否则将栈里面的符号出栈,并和数字栈进行计算,设置新的栈顶符号和优先级,一直到优先级低的全部弹出栈,循环停止 ,新的符号入栈
  b.如果 token是 "(",直接入栈
  c. 如果token是")"
          当stack_opt.top != "(",既没有找到最近的和右括号匹配的左括号
		  操作符弹出栈,并和操作数计算
		  最后将"C"也弹出去
		  ”)“不进栈,它的出现是为了消除掉最近的左括号) //循环外的pop是将左括号丢弃 
  d.剩下的情况就都是数字,直接进入操作数栈 
*/


#include <iostream>
#include <string>
#include <vector>
#include <stack>

using namespace std;

int priority(string opt)
{
	int p = 0;
	if(opt == "(")
		p = 1;
	if(opt == "+" || opt == "-")
		p = 2;
	if(opt == "*" || opt == "/")
		p = 3;
	return p;
}

void calculate(stack<int> &opdstack, string opt)
{
	if(opt == "+")
	{
		int ropd = opdstack.top();
		opdstack.pop();
		int lopd = opdstack.top();
		opdstack.pop();
		int result = lopd + ropd;
		opdstack.push(result);
	}
	if(opt == "-")
	{
		int ropd = opdstack.top();
		opdstack.pop();
		int lopd = opdstack.top();
		opdstack.pop();
		int result = lopd - ropd;
		opdstack.push(result);
	}
	if(opt == "*")
	{
		int ropd = opdstack.top();
		opdstack.pop();
		int lopd = opdstack.top();
		opdstack.pop();
		int result = lopd * ropd;
		opdstack.push(result);
	}
	if(opt == "/")
	{
		int ropd = opdstack.top();
		opdstack.pop();
		int lopd = opdstack.top();
		opdstack.pop();
		int result = lopd / ropd;
		opdstack.push(result);
	}
}



/*
*说明:
1.扫描表达式
  a.如果 token 是 "+" ,"-","*","/"
     a1.符号栈为空,直接入栈
	 a2.符号栈不空,比较token和栈顶符号的优先级
	    如果token的优先级高,直接入栈
		否则将栈里面的符号出栈,并和数字栈进行计算,设置新的栈顶符号和优先级,一直到优先级低的全部弹出栈,循环停止 ,新的符号入栈
  b.如果 token是 "(",直接入栈
  c. 如果token是")"
          当stack_opt.top != "(",既没有找到最近的和右括号匹配的左括号
		  操作符弹出栈,并和操作数计算
		  最后将"C"也弹出去
		  ”)“不进栈,它的出现是为了消除掉最近的左括号) //循环外的pop是将左括号丢弃 
  d.剩下的情况就都是数字,直接进入操作数栈 
*/

int calcuExpression(vector<string> vec)
{
	stack<int> stack_opd;
	stack<string> stack_opt;
	
	for(auto i = 0; i != vec.size(); ++i)
	{
		string token = vec[i];
		if(token == "+" || token == "-" || token == "*" || token == "/")
		{
			if(stack_opt.size() == 0)
				stack_opt.push(token);
			else
			 {
			 	int token_p = priority(token);
			 	string top_opt = stack_opt.top();
			 	int opt_p = priority(top_opt);
			 	if(token_p > opt_p)
			 		stack_opt.push(token);
			 	else
			 	  {
			 	  	while(token_p <= opt_p)
			 	  	{
			 	  		stack_opt.pop();
			 	  		calculate(stack_opd, top_opt);
			 	  		if(stack_opt.size() > 0)
			 	  		{
			 	  			top_opt = stack_opt.top();
			 	  			opt_p = priority(top_opt);
						   }
						else
						 	break;
					  }
					  stack_opt.push(token);
				   }
			 }
		}
		
		else if(token == "(")
			stack_opt.push(token);
		else if(token == ")")
		{
			while(stack_opt.top() != "(")
			{
				string top_opt = stack_opt.top();
				calculate(stack_opd,top_opt);
				stack_opt.pop();
			}
			stack_opt.pop();
		}
		else
		  stack_opd.push(atoi(token.c_str()));  
	}
	
	while(stack_opt.size() != 0)
	{
		string top_opt = stack_opt.top();
		calculate(stack_opd,top_opt);
		stack_opt.pop();
	}
	return stack_opd.top();
}

int main()
{
	vector<string> tokens =  {"(","1","+","2",")","*","3","/","(","2","-","1",")"};
	
	
     for(auto i = 0; i != tokens.size(); ++i)
     cout << tokens[i] << " ";
     cout << endl;
     cout << calcuExpression(tokens) << endl;
	return 0;
}



  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值