递归中这两种方式有什么区别?

时间:2014-12-18 23:24:35

标签: c recursion

这是我写的一个递归函数,可以计算硬币变换的方式,它可以很好地工作。

int cc(int n, int k)
{
  if (n < 0 || k == 0)
    return 0;
  else if (n == 0)
    return 1;
  else
  {
    /*** WAY 1 : START ***/
    s.stk[++s.top] = k;
    int tmp = cc(n - d[k - 1], k);
    s.top--;
    return tmp + cc(n, k - 1);
    /*** WAY 1 :  END  ***/
  }
}

但是,如果我更改两条评论之间的代码,为什么它会开始得到错误答案:

/*** WAY 2 ***/
return (s.stk[++s.top] = k, cc(n - d[k - 1], k)) + (s.top--, cc(n, k - 1));
//     |<-----             A             ----->|   |<-----    B    ----->|

Aren他们相当吗?

P.S。虽然这不是一种好的方式(第2种方式),但我只是想知道为什么它不起作用。

修改

虽然我们不知道AB会先做,但我尝试做一些实验。

结论是,return A+B;return B+A;都不会得到正确答案。

1 个答案:

答案 0 :(得分:2)

阅读@delnan给出的“未定义的行为和序列点”链接以获取详细信息。但最简单的解释是A + B之间没有序列点。因此无法保证A和B中的哪一个首先被评估。这就是为什么方式1和方式2不等同。

在你的情况下:

A = (s.stk[++s.top] = k, cc(n - d[k - 1], k))
B = (s.top--, cc(n, k - 1))

现在,对cc()的递归调用将在路径A上有时(在编译时而不是在运行时决定)在路径A上进行,有时在路径B上进行。因此,调用的顺序都被搞砸了。

您可能希望在函数顶部添加一个print语句,该语句将在新行上打印序列号和参数。然后使用相同的初始数据以方式1和方式2执行它。将输出收集到两个文本文件中。区分这两个文件,看看哪里出了问题。