题目链接简单计算器
方法一:
思路:先将中缀表达式转化为逆波兰(后缀表达式),然后通过栈来计算逆波兰的计算式的值。
其中中缀转为后缀采用的方法来自博客中缀表达式转换为后缀表达式(逆波兰表达式),其中也包含了求逆波兰表达式值的介绍。
同时不定长字符串的输入以及字符串的分割取值也是一个难点,以后需要好好总结一下有关字符串读入,处理和输出的技巧。
这里分割采用了Strtok()函数,相关用法参考
字符串函数之Strtok()函数,输入使用了gets()函数,读取一行字符串
代码如下:
#include <iostream>
#include <stack>
#include <vector>
#include <sstream>
#include <map>
#include <cstring>
using namespace std;
const int MAX = 205;
stack<string> p;
map<string, int> m;//用来标记运算符的优先级
vector<string> S;
double string2double(string s)//将string类型的转化为double类型
{
double n = 0;
for(int i=0; i<s.size(); i++)
{
n = n*10+s[i]-'0';
}
return n;
}
void transform2AntiP(char s[])//将中缀转换为逆波兰
{
char *ss = strtok(s, " ");
string a;
while(ss)
{
a = "";
for(int i=0; i<strlen(ss); i++)//转化为string,方便操作
a += ss[i];
ss = strtok(NULL, " ");
if(a=="+" || a=="-" || a=="*" || a=="/")
{
if(!p.empty())
{
while(m[a]<=m[p.top()])
{
S.push_back(p.top());
p.pop();
if(p.empty()) break;
}
}
p.push(a);
}
else
{
S.push_back(a);
}
}
while(!p.empty())
{
S.push_back(p.top());
p.pop();
}
}
void compute()//计算逆波兰表达式
{
stack<double> pq;
for(int i=0; i<S.size(); i++)
{
double a, b, c;
if(S[i]=="-")
{
a = pq.top(); pq.pop();
b = pq.top(); pq.pop();
c = b-a;
pq.push(c);
}
else if(S[i]=="+")
{
a = pq.top(); pq.pop();
b = pq.top(); pq.pop();
c = a+b;
pq.push(c);
}
else if(S[i]=="*")
{
a = pq.top(); pq.pop();
b = pq.top(); pq.pop();
c = a*b;
pq.push(c);
}
else if(S[i]=="/")
{
a = pq.top(); pq.pop();
b = pq.top(); pq.pop();
c = b/(a*1.0);
pq.push(c);
}
else
{
pq.push(string2double(S[i]));
}
}
printf("%.2f\n", pq.top());
pq.pop();
}
int main()
{
m.insert(make_pair("+", 0));
m.insert(make_pair("-", 0));
m.insert(make_pair("*", 1));
m.insert(make_pair("/", 1));
char s[MAX];
while(gets(s)!=NULL)//处理不定长输入字符串的模板
{
if(strlen(s)==1 && s[0]=='0') break;
transform2AntiP(s);
compute();
}
return 0;
}
方法二:参考九度OJ 1101 表达式求值(栈的应用)
思路:有数字栈和符号栈,读取数字时,数字入数字栈,读取符号时,当符号栈为空时,入符号栈;不为空时, 查看符号栈顶是否为 * 或 \ ,如果非空且栈顶运算符是*和/的话就立刻取出两个操作数做运算,然后当前符号入栈,这样能保证乘除法比加减法先算。这样的话不断处理完了乘除法,最后需要做的只是通过符号栈做整个数字栈的加减法。
#include <iostream>
#include <stack>
#include <string>
#include <cstdlib>
#include <cctype>
using namespace std;
int main()
{
string data;
string numStr = "";
while (cin >> data)
{
data += '#'; //表达式末尾添加结束符#
stack<double> num; //存放操作数
stack<char> op; //存放运算符
for (int i = 0; data[i]; ++i)
{
if(isdigit(data[i])) //取到整个数串
numStr += data[i];
else
{
num.push(atoi(numStr.c_str())); //数字入栈
numStr = "";
if (!op.empty()) //只取出乘法或除法运算符
{
char c = op.top();
if (c == '*') //处理乘法
{
op.pop();
int b = num.top();num.pop();
int a = num.top();num.pop();
num.push(a*b);
}
if (c == '/') //处理除法
{
op.pop();
int b = num.top();num.pop();
int a = num.top();num.pop();
num.push(a/b);
}
}
if(data[i] != '#') op.push(data[i]); //当前运算符入栈
}
}
while(!op.empty()) //处理剩余的加减法
{
char c = op.top();
if (c == '+')
{
op.pop();
int b = num.top();num.pop();
int a = num.top();num.pop();
num.push(a+b);
}
if (c == '-')
{
op.pop();
int b = num.top();num.pop();
int a = num.top();num.pop();
num.push(a-b);
}
}
cout << num.top() << endl;
}
return 0;
}