表达式求值
以求解2+5*(3-2)为例,按照数据结构课本上的思路,是创建两个栈,一个数字栈,一个符号栈,然后根据入栈的符号的优先级来不断出栈进行计算,理解起来是挺方便的,但是代码记起来有点复杂,尤其是还需要两个栈。
近日看了一个老师的另外一种解法,利用递归的方式解决,不需要利用栈,听起来贼神奇,并且也是比较好理解和记忆的,下面介绍下另外一个老师的方法。
对于表达式2+5*(3-2)而言,我们先判断这是一个什么式子,按照以往的经验,我们会说这是一个加法式,因为加法运算是这个式子中最后计算的。 ”+“把式子分为左右两部分,左边2,右边5 x(3-2);接着看右边这个式子,我们可以判断这是一个乘法式,判断方式如上;**” * “**也同样把式子分为两部分,左边为5,右边为(3-2);那求解最开始的综合式是否可以理解为f=a (operator) b,此处的operator可以是+、-、*、/中的任何一种情况;其中 a 和 b 的结果的求解方式和 f 的一样,所以,这是一个递归的过程。
确定递归求解的边界和递归过程:
递归边界
//此时表明输入的表达式不存在运算符,都是数字
if (op == -1) {
// int num = 0;
// for (int i = l; i < r; i++)
// {
// if (str[i]<'0' || str[i]>'9')
// continue;
// num = num * 10 + str[i] - '0';
// }
// return num;
}
递归过程,即逐步求解 a 与 b 的过程
此时该如何确定operator的位置?根据我们以往的经验,对一个综合式,计算顺序为先乘除后加减,右括号先计算括号里面的,所以先运算运算符最高的,对于我们开始的例子,应该是先计算(3-2);我们再回过来看开始的例子,例子的运算顺序是 -、*、+,然而递归的顺序是先开始的后返回,和入栈出栈的顺序很想,先入后出,所以我们先找运算符中优先级最低的,找到后确定左右的式子 a 和 b。然后再逐步确定 a 和 b 中的最低运算符,直到遍历完字符串的所有元素,
代码如下:
//定义两个变量 pri、cur_pri 记录先前运算符和当前运算符的高低,因为我们要找出运算符最低的那一个
//因为括号会改变运算符的顺序,定义一个变量 temp 来改变运算符的高低
int calc(char *str,int l,int r){
int op=-1; //记录最低操作符的初始位置
int pri=INF-1; //先前运算符的优先级
int cur_pri; //记录当前符号优先级
int temp=0; //定义括号改变运算符的变量
for(int i=l;i<r;i++){
cur_pri=INF;//定义当前运算符的初始大小
switch(str[i]){
//如果是运算符,则相应的改变当前运算符的大小
case '(':
temp +=100;
break;
case ')':
temp -=100;
break;
case '+': //此处是体现的case 并列,意味着case '+' 与下面的 case '-'执行相同的操作;直到遇到break;
case '-':
cur_pri = 1 + temp;
break;
case '*':
case '/':
cur_pri = 2 + temp;
break;
}
//如果当前运算符优先级小于等于先前的运算符优先级,则替换
if (cur_pri <= pri) {
//将op 指到当前的字符串字符的位置
op = i;
pri = cur_pri;
}
//根据op 的位置确定 a 和 b
int a = calc(str, l, op);
int b = calc(str, op + 1, r);
switch (str[op]) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
return 0;
}
如有不同见解,欢迎讨论