递归 - 试图理解

Posted

技术标签:

【中文标题】递归 - 试图理解【英文标题】:Recursion - trying to understand 【发布时间】:2012-01-06 10:21:29 【问题描述】:

我有下一个方法:

public static int maxFind(int [] a, int length)

  if (length == 1)
          return a[0];
  

  // recursively maxFind method on length-1
  int result = maxFind(a, length - 1);

  if (a[length - 1] > result)
    return a[length - 1];
  else
    return result;


我已经完成了这项工作,并且从我看到该方法的教程开始,我总是忘记递归的想法。我想如果有人能解释我这个方法的每一步 - 我会一劳永逸地明白这个想法。

示例 - 我的 arr 是:1,1,0,2)

当我们运行这个方法时,这里的步骤是什么?结果的价值是什么, (a, length-1) 的作用是什么? (我试过调试器,但它没有帮助我)

【问题讨论】:

为什么调试器没有帮助? 我很难理解 blueJ 的调试器。我会试试eclipse调试器。 好的,eclipse 调试器完成了这项工作。我怎么忘记了这个选项... Eclipse 有一个很好的调试器。如果您愿意,您仍然可以在 BlueJ 中进行开发,只需使用 eclipse 进行调试。 【参考方案1】:

让我看看我是否可以对这个主题有所了解。

在考虑递归时,它有助于(至少对我而言)以更具声明性的方式来考虑程序,这意味着,您可以考虑您要完成的工作,而不是考虑所需算法的每个步骤去完成它。

让我们看看你的例子,你需要在一个数组中找到最大值,所以我们将把这个问题分解成更小的问题。

如果 Array 的大小为 1,则只有一个元素......所以一个是最大值。很简单。

求最大值问题可以描述为:列表的一个元素与所有其他元素的最大值之间的较大值。

这就是您在其余代码中所做的事情。你将算法应用到从位置 0 到 length-1 的数组,然后比较返回值。

这些调用将创建一个递归树,这意味着将有几个调用“嵌套”,直到每个调用都以长度=1(基本情况)完成,并且然后,算法将开始重构答案。

真正理解递归算法的最好方法是抓起一张纸并模拟程序,为每次调用在纸上写下数组的值和“长度”的值,然后弄清楚会发生什么在每次调用最终达到基本情况之后。

对于 1,1,0,2,您基本上会得到一个调用链,例如:

max(maxFind(1,1,0), 2)

maxFind(1,1,0) 归结为:

max(maxFind(1,1), 0)

而 maxFind(1,1) 是

max(1,1)  = 1

然后这开始沸腾(这是上面的相反顺序):

max(1, 0) = 0
max(1, 2) = 2 

所以结果将是 2。

【讨论】:

感谢您的详细回答。我已经拿了纸做了,但我叠在了最后。让我看看我是不是错了。最后,我们(通过我的数组 - 1,1,0,2)从 if 语句中得到了问题 if (a[0] (=1) > result(=1)... 对吗?那么该方法如何记住结果的最大值是 2?或者我在纸上做的树上错了。对不起英语:)【参考方案2】:

我会逐步解释:

首先你调用带有参数 1,1,0,2 和 4 的方法

1) max_find([1,1,0,2],4) => 长度不是 1,所以 max_find 将被再次调用,长度为 4-1

2) max_find([1,1,0,2],3) => 长度不是 1,所以 max_find 将被再次调用,长度为 3-1

3) max_find([1,1,0,2],2) => 长度不是 1,所以 max_find 将被再次调用,长度为 2-1

4) max_find([1,1,0,2],1) => 长度为1,所以会返回a[0] 为1

5) 现在,第 3 步的代码会评估第 4 步的结果 => a[2-1] 不是 > 1,因此它返回 1

6) 现在,第 2 步的代码会评估第 3 步的结果 => a[3-1] 不是 > 1,因此它返回 1

7) 现在,第 1 步的代码会计算第 2 步的结果 => a[4-1] > 1,因此它返回 a[4-1],即 2

完成

【讨论】:

【参考方案3】:

结果的值是什么

这就是递归的重点:result 没有 one 值,这可能会让你感到困惑。结果的值依次为 1、1、1 和 2。

我们运行这个方法的步骤是什么?

会发生什么:

What is the max of: 1 ?  Result is: 1   
What is the max of: (1), 1 ?  Result is: 1
What is the max of: (1, 1), 0 ?  Result is: 1
What is the max of: (1, 1, 0), 2 ?  Result is: 2

请注意,在使用递归方法时,调试确实不是那么简单。有时将方法调用“缩进”到深度递归级别会更有帮助,就像我在这里回答的这个问题一样:

How do I solve the 'classic' knapsack algorithm recursively?

(当然,您需要以某种方式跟踪递归调用的“深度”)

(a, length-1) 的作用是什么? (我试过调试器但是 这对我没有帮助)

调试器可能对您没有帮助,因为该方法使用“技巧”来节省 Java 中的内存:基本上,通过指示您不应该解析整个数组来缩短输入。但是您仍然递归地将整个数组传递给该方法。这是一种“穷人用少一个元素获取列表的实用方法”; )

这里是一个链接,展示了如何在不同语言的 lot 中找到列表的最大值。其中一些,如 OCaml,以函数形式表示:

http://rosettacode.org/wiki/Greatest_element_of_a_list

三行OCaml(来源:***):

let my_max = function
    [] -> invalid_arg "empty list"
  | x::xs -> List.fold_left max x xs

【讨论】:

如果我能够选择 2 个正确答案...你和 pcalcao 和唐是伟大的。谢谢!!!【参考方案4】:

这个想法基本上是您只需稍微更改输入数据即可再次执行完全相同的操作。

代码本身很简单:

第一个if 检查递归结束 int result 行进行递归 最后你会寻找最大的元素并返回它。

【讨论】:

以上是关于递归 - 试图理解的主要内容,如果未能解决你的问题,请参考以下文章

试图理解这个动态递归子集和的时间复杂度

JavaScript:试图理解计算指数值的递归函数的 Else 语句

所有字谜 - 递归

如何理解二叉树中的递归

汉诺塔解题思路

关于最小割的进一步理解