【问题标题】:Recursion process递归过程
【发布时间】:2017-12-17 14:38:11
【问题描述】:

我的问题是关于递归的,我有点难以理解一点。我调试了一小段代码,我知道流程是如何工作的,但质疑为什么以及如何工作?我会解释我的疑问。

我知道这可能是一个愚蠢的问题,但请清除我这个问题。

检查代码 -:

#include <stdio.h>

void sum(int n);
void add(int number);

int main()
{
    int number, result;

    printf("Enter a positive integer: ");
    scanf("%d", &number);
    sum(number);
}

void  sum(int num)
{
    if (num!=0) {
        sum(num - 1); //(2-1) (1-1)
        sum(num - 1); // (1-1) (2-1)
        add(num);
    }

}

void add(int number){
    int a = 5;
    int c = 0;
    c = a+number;

    printf("%d ",c);
}

当我给用户输入 2 时,流程转到 if 条件 -> Valiadte -> 进入 -> 首先调用 sum (2-1) -> 再次上升 -> 验证 -> 首先调用sum (1-1) -> 退出 if -> 调用第二个 sum (1-1) -> 退出 if -> 调用 add 函数 -> 再次调用 sum现在 (2-1) -> 验证 if -> 首先调用 sum (1-1) -> 出去 -> 再次调用第二个 sum (1-1) -> 调用 add -> 退出.

Recursion 定义说——:当一个函数调用自己时它是一个递归,递归一直持续到满足某个条件来阻止它。

我的问题是为什么第二个总和被称为 2 次或更多次?我的意思是,如果您在第一次调用时看到它满足条件(1-1),那么它应该退出并只调用add,但在调用add 之后它再次调用(2-1)。第二个Sum 是否以相反的顺序被调用?

如果第一个被称为123 然后第二个必须去321,即使它满足条件?这是递归过程的实际工作方式吗?谁能解释一下这个概念?


对我的问题的一点更新。我删除了第二个内部函数调用,现在留下了一个内部递归函数。检查更新的代码-:

void sum(int num)
{

    if (num != 0) {
        sum(num - 1);
    }

    if (num==2) {
        printf("Back to memory address of 2 , you can exit out of function now ");
    }

}

Input = sum(2)。现在当sumsum(1-1)sum(0) -> exit if .我看到电话没有结束功能。 num 的值再次被遍历回 2 going(0-&gt;1&gt;2) -> 进入 if (num==2) -> 在控制台上打印 -> 退出函数。

这说明什么?如果我猜是不是这样 - 内部调用是pass by value而不是reference?因此,即使内部递归函数也在更新 num 的值,它并没有改变 memory address 的值,它仍然是 2

流程也是这样的 - :

sum(2)实际内存地址值->sum(1)复制值->sum(0)复制值。好的,现在我可以退出 if 了。

但是等等!!我无法退出功能,num 必须返回并使用实际内存地址值更新 - :

num = 0 , num=1 , num=2(That's what I was looking for ) 。伟大的!!功能失效。

这是怎么回事??我还是有点卡住了。

【问题讨论】:

  • 您发布的代码根本不进行任何递归,它只是读取一个数字然后退出。您既不调用 sum 也不调用 main 中的 add。
  • C 和 C++ 是两种截然不同的语言。请仅使用您实际编程语言的标签。
  • @SornelHaetir 抱歉让我更新一下。
  • @Someprogrammerdude 对不起先生会记住的。
  • 它调用sum 两次而不是一次的事实正是递归函数的定义方式。您确实可以在递归函数中进行多个递归调用。没有什么反对的。它只是完成了一种与只有一个算法不同的算法。事实上,这很常见,例如在树遍历函数中:traverse(node) { if (node == NULL) return; traverse(node-&gt;left); traverse(node-right); /* do something with current node */ }

标签: c recursion


【解决方案1】:

添加一些简单的printf 语句并跟踪全局depth 变量中的“调用深度”可以很好地表示正在发生的事情:

int depth = 0;
void sum(int num)
{
    for(int i = 0; i < depth; ++i) printf("\t");
    printf("-> sum | depth: %d | num: %d\n", depth, num);
    ++depth;

    if (num != 0) {
        sum(num - 1);
        sum(num - 1);
        add(num);
    }

    --depth;
}

输入2:

-> sum | depth: 0 | num: 2
    -> sum | depth: 1 | num: 1
        -> sum | depth: 2 | num: 0
        -> sum | depth: 2 | num: 0
        add: 6
    -> sum | depth: 1 | num: 1
        -> sum | depth: 2 | num: 0
        -> sum | depth: 2 | num: 0
        add: 6
    add: 7

您也可以在sum的末尾打印,查看函数何时退出:

-> sum | depth: 0 | num: 2
    -> sum | depth: 1 | num: 1
        -> sum | depth: 2 | num: 0
        <- sum | depth: 2 | num: 0
        -> sum | depth: 2 | num: 0
        <- sum | depth: 2 | num: 0
        add: 6
    <- sum | depth: 1 | num: 1
    -> sum | depth: 1 | num: 1
        -> sum | depth: 2 | num: 0
        <- sum | depth: 2 | num: 0
        -> sum | depth: 2 | num: 0
        <- sum | depth: 2 | num: 0
        add: 6
    <- sum | depth: 1 | num: 1
    add: 7
<- sum | depth: 0 | num: 2

live example on wandbox

【讨论】:

  • 谢谢这位先生,但你能给我一个流程的理论概念吗?我的意思是我的问题?为什么在设置条件后它会倒序而不是退出?从上面的解决方案我不明白。
  • 我不明白您所说的“逆序”是什么意思。通过查看上面的输出并仔细阅读代码,您有什么意想不到的发现?
  • oak 先生,给我一些时间让我运行并测试它。
  • @VittorioRomeo 我更新了。你能解释一下吗?
【解决方案2】:

那是因为你没有修改值

void  sum(int num)
{
    if (num!=0) {
        sum(num - 1); //(2-1) (1-1) mark this as call [a]
        sum(num - 1); // (1-1) (2-1) mark this as call [b]
        add(num);
    }
}

当你调用 sum(2) 时:

  • 函数调用 sum(1) 在 [a]
  • 因为 1 不是 0,所以它再次在 [a] 处递归调用 sum(0)
  • 您不修改数字,这就是为什么再次调用 [b] 处的 sum(0) 的原因
  • 然后调用 add(1),
  • 当它返回时,您刚刚在 [a] 调用中完成 sum(1)
  • 现在您在 [b] 处调用 sum(1),因为变量 num 仍然是 2,并且之前的调用没有修改它
  • 等等

【讨论】:

  • 是不是因为内部调用是按值调用而不是引用?
  • 和表达式 num - 1 不编辑值 num 本身
  • 这是因为每次调用递归函数时,都会在堆栈上为该函数放置一个内存块,并且当满足条件时它开始弹出。这就是为什么我看到它以相反的顺序进行。感谢您帮助简化它。+1
【解决方案3】:

正如你所拥有的那样,总和永远不会终止(如果你摆脱了第二个递归 称呼) 输入为 2 的调用序列为: 用 2 调用 sum if 计算结果为真,因此第一个总和被调用,参数为 1 if 再次为真,因此现在调用第一个总和,参数为 0 if 计算结果为假,所以现在第二个总和被调用,参数为 -1 第一个 if 评估为真,所以第一个 sum 用 -2 的参数调用 第一个 if 评估为真,所以第一个总和用 -3 调用。 . 我真的不明白你为什么要第二次调用 sum。

【讨论】:

  • 这对我来说似乎不是一个准确的诊断。
猜你喜欢
  • 1970-01-01
  • 2014-01-29
  • 1970-01-01
  • 2013-06-19
  • 2019-02-10
  • 2015-07-18
  • 2015-08-08
  • 2018-12-29
  • 1970-01-01
相关资源
最近更新 更多