中缀运算符即是一般常用的数学表达方式,如a+b等运算
后缀运算符,即将操作符放在两个操作数后面的表达式。
后缀运算符算法思想:遇到操作数则将其进栈,直至遇到操作符,将栈顶附近的两个元素提出,进行运算,将运算结果进栈,与后序操作数进行计算。
下图为abc-/]de*+(对应中缀表达式为a/(b-c)+d*e)的计算过程,其中a=6,b=4,c=2,d=3,e=2
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入:tokens = ["2","1","+","3","*"]
输出:9
解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入:tokens = ["4","13","5","/","+"]
输出:6
解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
输出:22
解释:该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
由于这里是字符串数组,C语言中字符串之间的比较不能用逻辑运算符==来判断,因此遍历字符串的时候判断是否是运算符需要用到库函数strcmp
int strcmp(const char *str1, const char *str2) 把 str1 所指向的字符串和 str2 所指向的字符串进行比较。
声明:int strcmp(const char *str1, const char *str2)该函数返回值如下:
- 如果返回值小于 0,则表示 str1 小于 str2。
- 如果返回值大于 0,则表示 str1 大于 str2。
- 如果返回值等于 0,则表示 str1 等于 str2。
通过strcmp函数我们就完成了对字符串元素的比较问题,接下来需要考虑字符串中数字的获取入栈问题,但是由于输入的是字符串,所以需要使用atoi函数将字符串转换为数字
int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。
声明:int atoi(const char *str)返回值:
该函数返回转换后的长整数,如果没有执行有效的转换,则返回零。
代码实现:
int evalRPN(char ** tokens, int tokensSize)
{
int *stack = malloc(sizeof(int) * tokensSize);
int top = -1;
for (int i = 0; i < tokensSize; i++) {
if ((strcmp(tokens[i], "+") == 0) || (strcmp(tokens[i], "-") == 0) || (strcmp(tokens[i], "*") == 0) || (strcmp(tokens[i], "/") == 0)) {
int num2 = stack[top--];
int num1 = stack[top--];
if (strcmp(tokens[i], "+") == 0)
stack[++top] = num1 + num2;
if (strcmp(tokens[i], "-") == 0)
stack[++top] = num1 - num2;
if (strcmp(tokens[i], "*") == 0)
stack[++top] = num1 * num2;
if (strcmp(tokens[i], "/") == 0)
stack[++top] = num1 / num2;
} else {
stack[++top] = atoi(tokens[i]);
}
}
return stack[top];
}
如果采用上图所示的代码进行调试,那么在一些特定的案例会报错
例如:当输入为["-128","-128","*","-128","*","-128","*","8","*","-1","*"]时
由报错可以得知,在第16行也就是乘法处发生了报错。
在32位和64位机器中,int占32位,取值范围为-2147483648~2147483647()
-128*-128*-128*-128*8*-1=-2,147,483,648
此时由于int类型的数据范围限制,会导致数据过大越界问题,此时采用强制类型转换,将其转换为long类型
int evalRPN(char ** tokens, int tokensSize)
{
int *stack = malloc(sizeof(int) * tokensSize);
int top = -1;
for (int i = 0; i < tokensSize; i++) {
if ((strcmp(tokens[i], "+") == 0) || (strcmp(tokens[i], "-") == 0) || (strcmp(tokens[i], "*") == 0) || (strcmp(tokens[i], "/") == 0)) {
int num2 = stack[top--];
int num1 = stack[top--];
if (strcmp(tokens[i], "+") == 0)
stack[++top] = num1 + num2;
if (strcmp(tokens[i], "-") == 0)
stack[++top] = num1 - num2;
if (strcmp(tokens[i], "*") == 0)
stack[++top] = (long)num1 * (long)num2;
if (strcmp(tokens[i], "/") == 0)
stack[++top] = num1 / num2;
} else {
stack[++top] = atoi(tokens[i]);
}
}
return stack[top];
}