需要帮助了解递归前缀评估程序

时间:2014-03-14 20:44:34

标签: c++ recursion prefix evaluator

这是我在教科书中找到的一段代码,用于使用递归来计算前缀表达式。我无法理解这段代码以及它经历的过程。

    char *a; int i;
    int eval()
      { int x = 0;
        while (a[i] == ' ') i++;
        if (a[i] == '+')
          { i++; return eval() + eval(); }
        if (a[i] == '*')
          { i++; return eval() * eval(); }
        while ((a[i] >= '0') && (a[i] <= '9'))
           x = 10*x + (a[i++] - '0');
        return x;
      }

我想我主要是对return语句以及它最终如何解决前缀表达式感到困惑。提前谢谢!

6 个答案:

答案 0 :(得分:1)

理解递归示例的最佳方法是通过一个示例:

char* a = "+11 4"

首先关闭,i初始化为0,因为没有默认初始值设定项。 i也是全球性的,因此对它的更新将影响eval()的所有调用。

i = 0, a[i] = '+'

没有前导空格,因此第一个while循环条件失败。第一个if语句成功,i递增为1并执行eval() + eval()。我们会一次评估这些,然后在得到结果后再回来。

i = 1, a[1] = '1'

同样,没有前导空格,所以第一个while循环失败。第一个和第二个if语句失败。在最后一个while循环中,'1'介于0和9之间(基于ascii值),因此x变为0 + a [1] - '0'或0 + 1 = 1.重要的是这里在i被读取后,a[i]递增,然后i递增。 while循环的下一次迭代添加到x。这里x = 10 * 1 + a [2] - '0'或10 + 1 = 11.使用正确的x值,我们可以退出eval()并返回第一个操作数的结果,再次在这里11。

i = 2, a[2] = '4'

与上一步一样,在eval()调用中执行的唯一语句是最后一个while循环。 x = 0 + a [2] - '0',或0 + 4 = 4.所以我们返回4.

此时控制流程返回到对eval()的原始调用,现在我们有两个操作数值。我们只需执行加法即可获得11 + 4 = 15,然后返回结果。

答案 1 :(得分:1)

每次调用eval()时,它都会计算从位置i开始的立即下一个表达式的值,并返回该值。

在eval内:
第一个while循环只是忽略所有空格 然后有3个案例:

(a)评估以+开头的表达式(即 A + B 的表达式,&#34; + A B&#34; 在前缀中

(b)评估以*开头的表达式(即 A * B =&#34; * A B&#34;

(c)评估整数值(即任何连续的数字序列)

最后的while循环负责案例(c)。

案例(a)的代码类似于案例(b)的代码。考虑案例(a):
如果我们遇到+号,就意味着我们需要添加下两个&#34; 的东西&#34;我们在序列中找到。 &#34; 事物&#34;可能是数字,或者它们本身可能是要评估的表达式(例如X + Y或X * Y)。

为了获得这些&#34; 的东西&#34;是,使用更新的i值调用函数eval()。每次调用eval()都将获取下一个表达式的值,并更新位置i。

因此,对eval()的两次连续调用获得了以下2个表达式的值 然后我们将+运算符应用于2个值,并返回结果。

这将有助于完成&#34; + * 2 3 * 4 5&#34; 等示例,这是(2 * 3)+的前缀表示法( 4 * 5)即可。

答案 2 :(得分:0)

所以这段代码只能吃+,*,空格和数字。它应该吃一个命令,可以是以下之一:

- + <op1> <op2>
- * <op1> <op2>
<number>

它获取一个指向字符串的指针,以及一个读取位置,该位置随着程序进入该字符串而递增。

   char *a; int i;
    int eval()
      { int x = 0;
        while (a[i] == ' ') i++; // it eats all spaces
        if (a[i] == '+') 
       /* if the program encounters '+', two operands are expected next. 
          The reading position i already points just before the place 
          from which you have to start reading the next operand 
          (which is what first eval() call will do). 
          After the first eval() is finished, 
          the reading position is moved to the begin of the second operand, 
          which will be read during the second eval() call. */
          { i++; return eval() + eval(); }
        if (a[i] == '*') // exactly the same, but for '*' operation.
          { i++; return eval() * eval(); }
        while ((a[i] >= '0') && (a[i] <= '9')) // here it eats all digit until something else is encountered.
           x = 10*x + (a[i++] - '0'); // every time the new digit is read, it multiplies the previously obtained number by 10 and adds the new digit.
        return x; 
        // base case: returning the number. Note that the reading position already moved past it. 
      }

答案 3 :(得分:0)

您给出的示例使用了几个全局变量。它们在函数范围之外持久存在,必须在调用函数之前初始化。 我应该初始化为0,以便从字符串的开头开始,前缀表达式是a中的字符串。

运算符是你的前缀,所以你应该是你的第一个非空白字符,如果你从一个数字(数字串)开始,那就是结果。

示例:a =&#34; + 15 450&#34;

eval() finds '+' at i = 1
    calls eval() 
        which finds '1' at i = 3 and then '5' 
        calculates x = 1 x 10 + 5 
    returns 15
    calls eval() 
        which finds '4' at i = 6 and then '5' and then '0'
        calclulates x = ((4 x 10) + 5) x 10) + 0
    returns 450
    calculates the '+' operator of 15 and 450
returns 465

返回值是找到的值或运算符的结果以及找到的后续结果。因此递归地,函数连续查看输入字符串并执行操作,直到字符串结束或找到了无效的字符。

答案 4 :(得分:0)

不是将代码分成块等等,我会尝试解释它尽可能简单的概念。

eval函数总是跳过空格,使其指向当前位置的数字字符('0' - >'9'),加法('+')或乘法('*')表达式字符串。

如果遇到一个数字,它会继续吃数字,直到达到非数字位数,以整数格式返回总结果。

如果它遇到运算符('+'和'*'),则需要两个整数,因此eval会自动调用两次以从表达式字符串中获取接下来的两个数字,并将该结果作为整数返回。

答案 5 :(得分:0)

汤中的一根头发可能是评价订单,参见https://www.securecoding.cert.org/confluence/display/seccode/EXP10-C.+Do+not+depend+on+the+order+of+evaluation+of+subexpressions+or+the+order+in+which+side+effects+take+place

没有在&#34; eval()+ eval()&#34;中指定哪个eval?好吧,首先评估。这对于可交换的运算符来说是好的,但是会失败 - 或/,因为作为副作用的eval()会使全局位置计数器前进,以便(在时间上)第二个eval获得(在空间中)第二个表达式。但这可能是(在太空中)第一个评估。

我觉得修复很简单;分配给一个临时计算并使用:

计算
if (a[i] == '-')
      { i++; int tmp = eval(); return tmp - eval(); }
相关问题