Basic Calculator
简单字符串计算器的实现
1.题目说明
本题大意为要求我们实现对有且只有加减号、括号作为运算符的字符串进行数学运算得出结果。
2.题意理解
由于本题只要求在字符串中有加减号而没有乘除号,这就使我们可以永远通过括号内优先作为优先级判断标准,从而不需要逆波兰表达式存储,也即不需要压栈、退栈等操作。然而,由于想将此题封装为一个通用的算法,并希望配合练习带有加减乘除、括号等所有运算符的逆波兰表达式计算问题,此题本人仍使用逆波兰表达式方法。虽然算法复杂度高于此题需要,但可以为后续使用作准备
3. 算法描述
此部分算法描述大可略过,因为想必读者均已熟悉如下套路:
通过栈结构将输入字符串转化为逆波兰表达式;
通过栈结构将波兰表达式计算成结果。
此算法毕竟是说起来简单,做起来难。因为其中有很多地方容易出错,造成编程者在Debug时所用的时间远大于编程时间。下面就对逆波兰表达式算法部分的关键之处进行剖析。
优先级判定:本人推荐使用7阶二维矩阵,直接存储’>’,’
数字存储:本例暂时只对正数进行运算,在防止出现两位数情况时,在遇到数字时设立标志位,若下一个字符还是数字,便将前一数字一同存储为数字元素,依此类推。
压栈退栈:若当前运算符优先级大于栈顶运算符优先级,将当前运算符压入;若小于,则将栈内所有比当前运算符优先级小的运算符弹出;若等于,说明是括号相遇,同时退栈。
class Solution
{
public:
static char Prior[7][7];//运算符优先级矩阵
int CodeOfOpnd(char
opnd)//运算符代号
{
switch (opnd)
{
case '+':
return 0;
case '-':
return 1;
case '*':
return 2;
case '/':
return 3;
case '(':
return 4;
case ')':
return 5;
case '#':
return 6;
}
}
double MathCalculate(int
op1, int op2,
char opnd)//运算符运算方法
{
switch (opnd)
{
case '+':
return op1 +
op2;
case '-':
return op2 -
op1;
case '*':
return op1 *
op2;
case '/':
return op2 /
op1;
}
}
int calculate(string
s)//计算函数
{
s.push_back('#');
stack<char>opnd;
opnd.push('#');
vector<int>save;
bool pre_is_num = false;
//逆波兰表达式建立
for (int i =
0; i <
s.size(); i++)
{
if (s[i]
>= '0' &&
s[i] <= '9')
{
if (pre_is_num == false)
{
save.push_back(s[i]
- '0');
}
else
{
save[save.size()
- 1]
= save[save.size()
- 1]
* 10 +
s[i]
- '0';
}
pre_is_num = true;//数字标志位
}
else if (s[i] ==
'+' || s[i] ==
'-' || s[i] ==
'*' || s[i] ==
'/' || s[i] ==
'(' || s[i] ==
')' || s[i] ==
'#')
{
while (Prior[CodeOfOpnd(opnd.top())][CodeOfOpnd(s[i])]
== '>')//若当前运算符优先级小于栈顶运算符优先级
{
save.push_back(opnd.top());//将弹出的运算符存入逆波兰表达式
opnd.pop();//不断弹出
}
if (Prior[CodeOfOpnd(opnd.top())][CodeOfOpnd(s[i])]
== '
{
opnd.push(s[i]);//压入当前运算符
}
if (Prior[CodeOfOpnd(opnd.top())][CodeOfOpnd(s[i])]
== '=')//若当前运算符优先级等于栈顶运算符优先级
{
opnd.pop();//只退栈
}
pre_is_num = false;
}
}
stack<double>Number;
//通过逆波兰表达式运算
for (int i
= 0; i
< save.size(); i++)
{
if (save[i]
>= 0 && save[i]
!= '+' && save[i]
!= '-' && save[i]
!= '*' && save[i]
!= '/')
{
Number.push(save[i]);
}
else
{
int op1 = Number.top();
Number.pop();
int op2 = Number.top();
Number.pop();
Number.push(MathCalculate(op1,
op2, save[i]));
}
}
int result = Number.top();
return result;
}
};
char Solution::Prior[7][7]
= { {
'>', '>', '', '>' }, {
'>', '>', '', '>' },
{ '>', '>', '>', '>', '', '>' }, {
'>', '>', '>', '>', '', '>' },
{ '
'*' }, { '>', '>', '>', '>', '*',
'>', '>' },
{ '
'=' } };