我自己在C中练习递归,我在网上找到了这个例子。 但有一点我不明白。
void singSongFor(int numberOfBottles)
{
if (numberOfBottles == 0) {
printf("There are simply no more bottles of beer on the wall.\n\n");
}
else {
printf("%d bottles of beer on the wall. %d bottles of beer.\n",
numberOfBottles, numberOfBottles);
int oneFewer = numberOfBottles - 1;
printf("Take one down, pass it around, %d bottles of beer on the wall.\n\n",
oneFewer);
singSongFor(oneFewer); // This function calls itself!
// Print a message just before the function ends
printf("Put a bottle in the recycling, %d empty bottles in the bin.\n",
numberOfBottles);
}
}
然后我使用main方法:
int main(int argc, const char * argv[])
{
singSongFor(4);
return 0;
}
输出就是这样:
墙上挂着4瓶啤酒。 4瓶啤酒。 拿下一个,将它传递给墙壁上的3瓶啤酒。 墙上挂着3瓶啤酒。 3瓶啤酒。 拿下一个,将它传递给墙壁上的2瓶啤酒。 墙上挂着2瓶啤酒。 2瓶啤酒。 拿下一个,将它传递给墙壁上的1瓶啤酒。 墙上挂着1瓶啤酒。 1瓶啤酒。 拿下一个,将它传递给墙上的0瓶啤酒。墙上不再有啤酒瓶了。
将一个瓶子放入回收处,在垃圾箱中放入一个空瓶子。
将一个瓶子放入回收处,在垃圾箱中放入2个空瓶子。
在回收箱中放入一个瓶子,在垃圾箱中放入3个空瓶子。
将一个瓶子放入回收箱中,将4个空瓶放入垃圾箱。
我非常了解第一部分,直到我说到“墙上再也没有啤酒瓶。后来我不明白可变数量的瓶子从1增加到4。
答案 0 :(得分:6)
较小的啤酒瓶(及其相应的回收)具有内在功能。您的功能树如下所示:
4 bottles of beer on the wall. 4 bottles of beer. Take one down, pass it around, 3 bottles of beer on the wall.
| 3 bottles of beer on the wall. 3 bottles of beer. Take one down, pass it around, 2 bottles of beer on the wall.
| | 2 bottles of beer on the wall. 2 bottles of beer. Take one down, pass it around, 1 bottles of beer on the wall.
| | | 1 bottles of beer on the wall. 1 bottles of beer. Take one down, pass it around, 0 bottles of beer on the wall.
| | | | There are simply no more bottles of beer on the wall.
| | | Put a bottle in the recycling, 1 empty bottles in the bin.
| | Put a bottle in the recycling, 2 empty bottles in the bin.
| Put a bottle in the recycling, 3 empty bottles in the bin.
Put a bottle in the recycling, 4 empty bottles in the bin.
答案 1 :(得分:4)
逐步完成此函数在调试器中的作用,您将看到此递归的确切工作原理。我不是迂腐;我真的想不出更好的方式来说明这是做什么比参考这种互动方法。
答案 2 :(得分:4)
只是简单的图片说明:
答案 3 :(得分:3)
请注意,最后一个printf
使用numberOfBottles
变量,并且永远不会修改。因此,从打印oneFewer
瓶返回后,它将使用numberOfBottles
打印回收文本。请记住,每次调用函数时都会有一个局部变量的不同版本。
如果缩进对函数的调用,可以看得更容易:
4 bottles of beer on the wall...
3 bottles of beer on the wall...
2 bottles of beer on the wall...
1 bottles of beer on the wall...
There are simply no more bottles of beer on the wall.
Put a bottle in the recycling, 1 empty bottles in the bin.
Put a bottle in the recycling, 2 empty bottles in the bin.
Put a bottle in the recycling, 3 empty bottles in the bin.
Put a bottle in the recycling, 4 empty bottles in the bin.
现在,从同一个函数调用中写入从同一列开始的每一行。你看到瓶子和回收coindice的数量如何?那是因为两者都使用相同的变量:numberOfBottles
。
答案 4 :(得分:2)
在递归调用返回后运行recycle语句。
每个递归调用最终都会完成,程序将继续执行后面的循环语句,每个语句都有自己的局部变量值。
答案 5 :(得分:2)
使用递归,您可以将递归调用之前的所有内容视为前向循环,并将调用后的所有内容视为后向循环。 (尾递归 - 在函数末尾再次调用函数 - 通常由编译器优化为简单的正向循环。)
这种方法的工作方式是将每个旧函数的参数压入堆栈,并在全部返回时弹出。请记住,堆栈是后进先出。因此,从4开始,它按4,然后是3,然后是2,然后是1.当函数返回时,堆栈开始展开,所以你再次以相反的顺序看到参数:1,2,3,4。
答案 6 :(得分:2)
它以这种方式工作的原因是,numberOfBottles大于1的singSongFor()
的每次调用将依次递归调用singSongFor()
,直到numberOfBottles为0.此时printf("There are simply no more bottles of beer on the wall.\n\n")
到达并且该函数将完成,传递给调用函数,该函数将传入1的参数,然后到达printf("Put a bottle in the recycling, %d empty bottles in the bin.\n", numberOfBottles);
并且自身完成,返回singSongFor(2)
...等等直到你回到你的原始号码,在这种情况下为4。