练习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;
}