【问题标题】:Can someone please explain me how this type of recursion works?有人可以解释一下这种递归是如何工作的吗?
【发布时间】:2014-08-06 15:32:30
【问题描述】:

我在递归中遇到了这个问题。我无法弄清楚它是如何工作的。我了解递归的基础知识,但这完全让我感到困惑。请帮忙。

main() { 
    foo(3); 
}

void foo(int x) {
    if (x >= 1) {
        foo(--x);
        printf("%d", x);
        foo(--x);
    }
}

我认为这个程序不会打印任何东西,但它会打印 0120

第一次调用 foo(--3) 即 foo(2) 不是跳转到函数的开头并递归到 3 递减到 0 吗?

请解释一下这是如何工作的。

【问题讨论】:

  • x 是按值传递的,而不是按引用传递的。其他调用中的--x不影响当前调用。

标签: c recursion


【解决方案1】:

第一次调用foo()可以用递归树来解释:

  prints (in reverse order)

    2 <----------  foo(3)
                  /      \
    1 <----- foo(2)       foo(1) -----> 0
             /   \        /     \
    0 <-- foo(1) foo(0)  foo(0)  foo(-1)
         /    \ 
      foo(0)   foo(-1)

首先,左子树将被评估并打印012,然后右子树将被评估并打印0。最后得到输出:

0120

【讨论】:

  • 这种递归树原理是否适用于所有形式的递归?我的意思是如果 foo(3) 调用超过 2 个函数会怎样?
  • @Tania;对于简单的递归,您可以绘制,但对于复杂的,它会更复杂。
  • 好的,但是还有其他定义的方法来解析复杂的递归吗?除了这些技巧。例如,使用堆栈?在同样的问题中,如果 foo(4) 被传递,我得到一个 19 位的输出。
  • @Tania;阅读:Tracing Recursive Functions。这会很有帮助。
  • 我试图通读这篇文章,但对我来说有点复杂。我没有得到他们的方框和圆圈符号。你能解释一下 foo(4) 是如何以同样的方式工作的吗?我尝试绘制一棵树并跟踪结果,但最终得到 3012000 作为答案,这是错误的。
【解决方案2】:

所以 foo(3) 是:

foo(2)
print 2
foo(1)

而 foo(2) 是:

foo(1)
print 1
foo(0)

而 foo(1) 是:

foo(0)
print 0
foo(-1)

现在 foo(0) 和 foo(-1) 是无操作的,所以 foo(1) 是:

print 0

foo(2) 是从哪里来的:

print 0
print 1

而 foo(3) 是:

print 0
print 1
print 2
print 0

这会给你观察到的输出。

【讨论】:

    【解决方案3】:

    这是预期的输出。下一个函数调用被压入堆栈,直到上一个函数调用返回时才会执行 printf 语句。

    foo(3) --> foo(2) --> foo(1) --> foo(0)
    

    现在 x 不 >=1,因此不再有函数调用,并且 foo(0) 被弹出堆栈。来自 foo(1) 的 printf 语句被执行并且 0(因为 x 值被递减)进入标准输出。另一个 foo() 调用:

    foo(3) --> foo(2) --> foo(1) --> foo(-1)
                                 //  ^^ second foo() call from foo(1)
    

    当前输出:

    0
    

    这没有任何作用。 foo(-1) 和 foo(1) 从堆栈中弹出。
    现在 printf 从 foo(2) 调用,1 进入标准输出。

    调用 foo(0)。

    foo(3) --> foo(2) --> foo(0)
                      //  ^^ second foo() call from foo(2)
    

    当前输出:

    01
    

    foo(0) 什么都不做,然后弹出堆栈的 foo(0) 和 foo(2)。

    现在我们在 foo(3) 中。打印 2 并调用 foo(1)。

    foo(3) --> foo(1)
           //  ^^ second foo() call from foo(3)
    

    当前输出:

    012
    

    foo(1) 调用 foo(0) 然后打印 0 然后调用 foo(-1)。现在所有剩余的 foo 都从堆栈中弹出,输出为 0120。


    @hacks - 看到这个程序。有对 foo(-1) 的调用。

    #include <stdio.h>
    
    void foo(int);
    
    int main() { 
        foo(3); 
        return 0;
    }
    
    void foo(int x) {
        if (x >= 1) {
            printf("executing foo with x = %d\n",x-1);
            foo(--x);
            printf("original output: %d\n", x);
            printf("executing foo with x = %d\n",x-1);
            foo(--x);
        }
    }
    

    输出:

    executing foo with x = 2
    executing foo with x = 1
    executing foo with x = 0
    original output: 0
    executing foo with x = -1
    original output: 1
    executing foo with x = 0
    original output: 2
    executing foo with x = 1
    executing foo with x = 0
    original output: 0
    executing foo with x = -1
    

    【讨论】:

    • 真的吗?我以为在foo(1) 中你已经在if 语句中,在foo(0) 返回后,执行printf 然后调用foo(-1)
    • 我的错误。是的,我错了。删除我的反对票。但是您的解释仍然不清楚。
    • 我不明白你解释的堆栈部分。您能否再次解释一下,忘记每个调用的输出?我只需要知道函数是如何被压入堆栈并弹出的。
    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    相关资源
    最近更新 更多