【问题标题】:How does recursion work when there are two recursive calls in a same statement?当同一语句中有两个递归调用时,递归如何工作?
【发布时间】:2018-11-07 09:00:00
【问题描述】:

我最近开始研究算法和数据结构。我遇到了斐波那契问题及其使用递归的解决方案。但就是这样。我理解当只有一个时递归调用是如何工作的(比如在一个数字的阶乘中)。函数调用会不断堆积,直到它们达到基本情况,然后它们开始以一为单位解开到所需的答案。

但是我不明白的是,当 f(n)+f(n/2) 这样的表达式中有两个递归调用时,递归是如何工作的。我的意思是首先解决哪个呼叫,以及何时解决第二个呼叫。如果将此表达式分配给语句,如何计算总和? 我自己写了一个小代码来破译这个。

#include <iostream>
#include <string>


int main()
{
  int recursionTest(int n, char c);
  int x;
  std::cin>>x;
  std::cout<<"Ans:"<<recursionTest(x,'c');

}


int recursionTest(int n,char c)
{
   int result=0;
   if(n==0)
    return 1;
   std::cout<<n<<":"<<c<<std::endl;
   result=recursionTest(n/2,'L')+recursionTest(n/3,'R');////I cant figure 
                                                           out the flow of 
                                                           control here!!!
   return result;
}

我得到了以下输出。

24
24:c
12:L
6:L
3:L
1:L
1:R
2:R
1:L
4:R
2:L
1:L
1:R
8:R
4:L
2:L
1:L
1:R
2:R
1:L
Ans:20

所以我明白了,它是一个树形结构。但我仍然不知道我们如何得到 20 作为答案(输入 = 24)。 sum 表达式是如何工作的,它是什么,我如何查看树结构并生成相同的输出?

【问题讨论】:

标签: c++ recursion fibonacci


【解决方案1】:

+ 运算符的两个子表达式的求值方式没有明确的顺序。编译器可以发出代码来先评估一个,然后再评估另一个。它甚至可以将一侧的一些计算与另一侧的计算交错。例如,它可以计算n/3,然后是n/2,然后是右函数调用,最后是左函数调用。

流程控制就像一个单一的递归案例,然后是另一个单一的案例。所以,你的线:

result=recursionTest(n/2,'L')+recursionTest(n/3,'R');

实际上等同于:

int left = recursionTest(n/2,'L');
int right = recursionTest(n/3,'R');
result = left + right;

除了在我的版本中暗示左函数调用保证在右函数调用之前被评估。

【讨论】:

  • 好的,你写left+right的时候,调用的堆叠顺序是什么?首先 int left=() 被堆叠直到用尽,然后 int right=() 被堆叠直到用尽,在第三行左 + 右,这是如何评估的?谁先被处决?
  • 第三行只是两个ints的简单相加。评估只是添加数字。很可能,这是一条指令。没有关于该陈述的评估问题的顺序。
  • 20 答案如何?按照这个逻辑,它应该是整棵树 ryt 的总和?
  • 在你的图中,你有①节点作为叶子,但这是不对的。如果recursionTest() 用1 调用,它将进入递归语句。每个①节点将有两个⓪子节点。只有⓪节点可以是叶子。此外,每个非叶必须总是有两个孩子,因为递归语句总是进行两次递归调用。只有一个②节点有一个⓪子节点。他们都应该拥有它们。总和将是树中 ⓪ 叶节点的计数(因为只有 ⓪ 节点对总和贡献了“新”数量,并且该数量始终为 1)。
【解决方案2】:

这里运算符优先级会起作用

f(n) + f(n/2);

在上面的代码中,sn-p f(n) 将首先被调用,然后是 f(n/2)。基本上算术运算符从左到右编译。 如果您想通过打印 n value 来调试代码,请在函数 f(int) 中使用 printf 语句。这样你就可以掌握代码的窍门了

【讨论】:

  • 不能保证f(n) 会在f(n/2) 之前被调用。编译器可以先调用任意一个。
  • 链接中没有任何内容表明f(n) 将在f(n/2) 之前进行评估。不要混淆从左到右的关联性和从左到右的求值顺序。
猜你喜欢
  • 2012-10-06
  • 2021-04-28
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
  • 1970-01-01
  • 2020-01-04
  • 2010-09-28
  • 2018-03-12
相关资源
最近更新 更多