【问题标题】:difficulty in understanding successive recursive calls难以理解连续的递归调用
【发布时间】:2015-10-09 21:45:08
【问题描述】:

我试图理解以下程序,其中存在连续的递归函数调用,但在跟踪如何加载大头钉时感到困惑。

void func(char*);  // function prototype

int main(){
    func("123");
    return 0;
}

void func(char a[]){
    if(a[1]=='\0')
        return;
    func(a+1);
    func(a+1);
    printf("%c",a[1]);
}

这个的输出是 3 3 2

如果有人能就此提出建议,将不胜感激......

这种多重递归调用是否有任何好处或在特定问题领域找到应用......?

【问题讨论】:

标签: c recursion stack


【解决方案1】:

只需将自己置于 CPU 的位置并逐行执行(或使用调试器来帮助完成该任务)。

第一个电话是

func("123")

这个调用不满足终止条件a[1] == '\0',所以调用

func("23");

依次调用func("23")

func("3")

满足返回条件。因此,该调用返回到前一个调用者 func("23")。

func("23") 由于这些行而继续对 func("3") 进行另一次调用

func(a+1);
func(a+1);

在你的脑海中继续执行这个程序的过程,并写下每次调用printf 的内容。这将解释你的输出。

更新

请注意,对 printf() 的调用发生在 递归调用之后,例如打电话给

func("123")

会像这样进行

  • 输入 func("123")
  • 不满足终止条件
  • 调用 func("23")
  • 再次调用 func("23")
  • Printf("3")(即 a[1])
  • 返回

【讨论】:

  • 感谢@Eric,我如何将 printf 函数调用与对 func()..的调用关联起来?
  • 对于 func() 的每次调用,只要 func() 的参数由于 if (a[1] == '\0') return; 而超过一个字符,最终都会调用 printf()。棘手的部分是 printf() 将在 两次调用func(a+1) 之后被调用。它真的可以归结为“玩 CPU”,然后一步步完成。将其打印在纸上并使用铅笔逐行跟踪可能会有所帮助。如果您使用铅笔,请记下每次调用的 func() 参数是什么,以帮助您跟踪。
【解决方案2】:

发布的代码是一个设计不佳的递归实例。

以下代码具有正确的“尾”递归形式。

通过将反转的字符串传递回 main 并让 main 打印它可以做得更好。

它反转了 main() 传递给 func() 的字符串的顺序

请在询问运行时问题时,发布编译代码,包括头文件必要的#includes,这样我们就不会猜测要包含哪些头文件

#include <stdio.h>

void func(char*);  // function prototype

int main(){
    func("123");
    return 0;
}

void func(char a[])
{
    if(a[1]=='\0')   // check for end of recursive sequence
    {
        printf( "%c", a[0] ); // last tail action
        return;
    }

    func(a+1);    // step+next recursion
    printf( "%c", a[0] ); // tail action
    return;
}

【讨论】:

    【解决方案3】:

    递归可以简单理解如下。

    例如:

    Func(int a){
        while(a>1)
            return a * func(a-1);
    }
    

    假设a = 5

    结果是它返回5 * func(4)

    现在func(4) 返回4 * func(3) 并继续这样下去。

    查看this example for use of recursion in fibonacci series

    【讨论】:

      【解决方案4】:

      使用断点进行调试是理解递归的一种方式。另一种方法是绘制递归调用树。

      从图中可以看出,在level0之后的每一层,由于这两行代码,printf语句出现在每两个节点之后:

      func(a+1);
      func(a+1);
      

      一般来说,对于任何长度大于 0 的输入字符串,这都会变成一棵完美的二叉树。节点总数由以下公式给出:

      2^(k+1) - 1 // k is the depth; here k = 2
      

      执行的printf语句总数可以通过这个公式得到:

      2^k - 1 // For k=2, there will be 3 printf statements each printing 3,3,2 respectively
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-22
        • 1970-01-01
        • 2016-10-14
        • 2013-09-29
        • 1970-01-01
        相关资源
        最近更新 更多