一、题目描述
二、解题思路
根据运算法则我们可以知道,优先计算括号里面的,其次计算乘法和除法,同等优先级的话需要从左到右顺序计算。因此本问题我们不仅需要解决优先级的问题,以及括号的问题。
在此之前,可以去搜索了解一下后缀表达式。
首先我们定义两个栈:
数据栈nums[]:存放所有数字操作栈ops[]:存放除数字外的符号,包括+-*/和括号
接着对字符串从前往后依次遍历,这时候会遇到一下几种字符:
-
空格:跳过
-
数字:把数字字符转换为整型数字,并压入
nums[]栈中- 如果是个位数,则可以直接入栈,但是我们需要的是不管几位数都能进行运算。
- 我们可以每次记暂存值
num = 0 - 当读取到一个数字
s[i]时,更新num = num*10 + (s[i] - '0'),这样子就完成了字符转数字,且保证了能够整体取出连续数字。 - 那么什么时候压入栈中呢?那就是下一个字符是字符串末尾,或下一个字符不是数字的时候,我们就可以把num这个数字压进
nums[]中了(压栈后需将num清零)
-
左括号(:直接压入
ops[]就可以了,作为括号内计算结束的标志 -
右括号):此时可以把括号内的计算完成,每次
ops[]出栈一个运算符,nums[]就出栈两个数字来进行运算,并把计算结果重新压入栈中,一直持续到从ops[]读到一个'('为止。最后把左括号出栈。 -
运算符:前面解决了括号问题,这里就需要解决+-*/优先级的问题了
- 我们首先把
'#'字符压入ops[]栈中,其本身没有意义,但是我们会赋予它的优先级为最低的。 - 当我们准备将一个运算符
s[i]压入栈中的时候,我们需要先将s[i]与栈顶运算符ops[opsTop]的级别进行比较,如果s[i]的级别低于栈顶元素的时候,我们就先将栈顶运算符出栈,同时nums[]也出栈两个数据计算结果,计算完成后把数字进栈。当级别高于栈顶元素的时候,就可以直接压栈了。 - 那怎么实现相等优先级从左往右计算呢?所谓的从左往右计算,就是说前面的先计算完成,我才可以计算。因此,
s[i]不可以压栈的情况是s[i]的级别小于或等于栈顶元素的级别,在此条件下,我们都会先把前面的计算完成后,才会把s[i]压入栈中 - 举个例子:"2 + 3 * 1 + 2"
nums[] = {2},ops[] = {#},读+,因为+的级别高于#,因此可以直接压栈;*级别高于+,可以直接入栈。此时nums[] = {2, 3, 1}, ops[] ={#, + , *}- 继续遍历字符串得到 + ,但是+级别低于*,因此会将''出栈,计算结果。‘’出栈完成后,+的级别和+号相等,此时应该从左往右算,因此会继续对
ops[]和nums[]出栈,计算结果。 - 当+级别大于栈顶元素时,才会将+入栈,此时
nums[] = {5}, ops[] = {#, +}
- 我们首先把
三、代码实现
long nums[100]; //最好使用long型,因为两个int相加相乘可能会超出范围
char ops[100];
int numsTop = -1;
int opsTop = -1;
// 运算符优先级
int priority(char c) {
if (c == '+' || c == '-')
return 1;
else if (c == '*' || c == '/')
return 2;
return 0; //'#'或'('的优先级
}
// 出栈计算
long calc(char c) {
// 出栈两个数字
int a = nums[numsTop--];
int b = nums[numsTop--];
int res = 0;
// 计算结果
switch (c) {
case '+': res = a + b; break;
case '-': res = b - a; break; //注意是 b - a
case '*': res = a * b; break;
case '/': res = b / a; break; //注意是 b / a
default: break;
}
return res;
}
int solve(char* s ) {
ops[opsTop++] = '#'; // 默认#为最低优先级
int i = 0;
int num = 0;
long tmp;
while (s[i] != '\0') {
// 遇到空格,直接跳过
while (s[i] == ' ')
i++;
// 遇到数字字符
if (s[i] >= '0' && s[i] <= '9') {
num = num * 10 + (s[i] - '0');
// 到达末尾或后面不是数字,则数字入栈
if (s[i + 1] == '\0' || (s[i + 1] < '0' || s[i + 1] > '9')) {
nums[++numsTop] = num;
num = 0; //清零,方便下一个数的读取
}
// 处理下一个字符
i++;
continue;
}
// 遇到左括号
else if (s[i] == '(') {
// 直接入栈
ops[++opsTop] = s[i];
// 处理下一个字符
i++;
continue;
}
// 遇到右括号
else if (s[i] == ')') {
// 出栈计算
while (ops[opsTop] != '(') {
tmp = calc(ops[opsTop--]);
// 计算结果入栈
nums[++numsTop] = tmp;
}
// 左括号出栈
opsTop--;
// 处理下一个字符
i++;
continue;
}
// 遇到运算符
else {
// 如果当前运算符优先级小于或等于栈顶优先级,则出栈计算
//相等优先级时,需要从左往右算,因此也要把前面的计算好后才能将新的运算符压栈
while (priority(s[i]) <= priority(ops[opsTop])) {
tmp = calc(ops[opsTop--]);
// 计算结果入栈
nums[++numsTop] = tmp;
}
// 将当前运算符入栈
ops[++opsTop] = s[i];
// 处理下一个字符
i++;
}
}
// 处理剩余运算符
while (opsTop > 0) {
tmp = calc(ops[opsTop--]);
nums[++numsTop] = tmp;
}
//返回最终运算结果
return nums[0];
}