这是我写的一个递归函数,可以计算硬币变换的方式,它可以很好地工作。
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种方式),但我只是想知道为什么它不起作用。
修改
虽然我们不知道A
或B
会先做,但我尝试做一些实验。
结论是,return A+B;
和return B+A;
都不会得到正确答案。
答案 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执行它。将输出收集到两个文本文件中。区分这两个文件,看看哪里出了问题。