最近遇到一个问题,设计一个简易计算器,输入一个字符串,有加减乘除括号运算,求计算结果。比如输入一个很长的字符串
3+(((5+9*(4+3)+5)*6+(4*5*4))),我们在计算的时候先括号,再乘除,最后加减。计算机会从左到右依次扫描字符串,遇到低优先级的先不计算,直到遇到更低优先级的,比如先前有个4*6没有计算,再次扫描下一个字符串遇到了+号,我们就不必继续保存不计算了而是先把4*6计算完,得到24+再继续扫描,
设计思想,利用两个栈一个是符号栈,一个是数字栈,遇到低优先级的就弹栈计算再入栈,当然还要分情况,比如栈顶是左括号,再来一个加号也不能弹栈计算,如果符号栈顶是*,再来一个+那就可以弹栈计算了,自己动手划两个栈就明白了,我就不划了,源代码如下。代码没有做差错处理,默认输出正确的表达式,差错处理请读者自行在相应位置加入代码。另外只能计算整数算式,没考虑小数
注意如果代码注释没理解自行画两个栈,一个符号栈,一个操作数栈,然后观察下进出栈情况就很清楚了。我之前划过,但是不知道放哪了,懒得再画了。
#include<iostream>
#include<stdio.h>
#include<stack>
using namespace std;
using std::stack;
int priority(char c);
bool have_higher_priority(char a, char b);
int cal(int left, char op, int right);
int main()
{
char expr[100]="3+(((5+9*(4+3)+5)*6+(4*5*4)))";//存放输入的字符串
stack<int> operand_stack;//操作数栈
stack<char>operator_stack;//运算符号栈
int i;
int j;
int num, left_operand, right_operand;
char op='\0';//上一个运算符
num =0;
//cin >> expr;
for (i = 0; expr[i] != '\0'; i++)
{
if (expr[i] == '+' || expr[i] == '-' || expr[i] == '*' || expr[i] == '/' || expr[i] == '(' || expr[i] == ')')//如果是符号
{
if (expr[i] == '(')//如果接下来的符号是左括号,直接入栈
{
operator_stack.push(expr[i]);
}
else if (expr[i] == ')')//如果接下来的符号是右括号,一直弹栈操作,直到碰到左括号
{
while (operator_stack.top() != '(')
{
right_operand = operand_stack.top();
operand_stack.pop();
left_operand = operand_stack.top();
operand_stack.pop();
op=operator_stack.top();
operator_stack.pop();
operand_stack.push(cal(left_operand, op, right_operand));
}
operator_stack.pop();
}
else//如果是其他操作符,判断优先级
{
if (operator_stack.empty())//符号栈为空直接进栈
{
operator_stack.push(expr[i]);
}
else//操作符栈不为空
{
while (!operator_stack.empty()&&have_higher_priority(operator_stack.top(), expr[i])&&operator_stack.top()!='(')//栈顶元素优先级比当前运算符优先级高,且栈顶符号不是左括号
{ //弹栈计算
right_operand = operand_stack.top();
operand_stack.pop();
left_operand = operand_stack.top();
operand_stack.pop();
op = operator_stack.top();
operator_stack.pop();
operand_stack.push(cal(left_operand, op, right_operand));
}
operator_stack.push(expr[i]);
}
}
}
if ((expr[i] - '0') >= 0 && (expr[i] - '0') <= 9)//如果是数字
{
while((expr[i] - '0') >= 0 && (expr[i] - '0') <= 9)
{
num=10*num+(expr[i] - '0');
i++;
}
operand_stack.push(num);
i--;
num=0;
}
}
while (!operator_stack.empty())
{
right_operand = operand_stack.top();
operand_stack.pop();
left_operand = operand_stack.top();
operand_stack.pop();
op = operator_stack.top();
operator_stack.pop();
operand_stack.push(cal(left_operand, op, right_operand));
}
printf("%d", operand_stack.top());
getchar();
getchar();
}
int priority(char c)
{
switch (c)
{
case'+':
case'-':
return 1;
case'*':
case'/':
return 2;
case'(':
case')':
return 3;
}
}
bool have_higher_priority(char a, char b)
{
if (priority(a) >= priority(b))
{
return true;
}
else
{
return false;
}
}
int cal(int left, char op, int right)
{
switch (op)
{
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
}
}