【问题标题】:Problems with understanding recursion理解递归的问题
【发布时间】:2014-01-28 17:17:14
【问题描述】:

我在理解递归方面有问题,我没有在书籍和教程中得到解释。下面的例子在一个列表中找到了最大值,这里我卡在第二行,我根本不明白max([H|T], Max) when H > Max ->之后发生了什么

如果我能对代码中的所有步骤进行解释,我将不胜感激,例如为什么会出现 -> max(T, H);-> Max.

max([H|T]) -> max(T, H).

max([H|T], Max) when H > Max -> max(T, H);
max([_|T], Max)              -> max(T, Max);
max([],    Max)              -> Max.

非常感谢! E.

【问题讨论】:

标签: recursion erlang


【解决方案1】:

我试图一步一步地解释。假设您有一个列表:[2, 3, 1]

  1. max([2, 3, 1]).

  2. H=2 , T=[3, 1]
    max([H|T]) -> max(T, H).

  3. H=3, T=[1], Max=2
    max([H|T], Max) when H > Max -> max(T, H);
    这里 when 块说:如果 H 大于 Max 则再次调用 max 函数作为 max([1], 3)。

  4. 我们又来了,但值不同:
    H=1, T=[], Max=3
    max([H|T], Max) when H > Max -> max(T, H);
    1 > 3false 所以当块失败并尝试下一个最大函数定义时,会导致第 5 步。

  5. 我们知道 H 小于 Max,因为第 4 步失败,所以我们忽略它。
    T = [], Max=3
    max([_|T], Max) -> max(T, Max);

  6. 我们正在匹配最后一个函数定义,它说找到最大元素:
    [] = [], Max = 3
    max([], Max) -> Max.

【讨论】:

  • 我很喜欢这个解释,但是第三步怎么发现Max=2呢?
  • @Eri 那是因为它被第二步传递为2(看到H=2?)。
  • 我一定是盲人或只是愚蠢,但我不知道第二步 Max 的哪个位置传递为 2。或者如何传递。
  • 第二步,H=2 , T=[3, 1],当你打电话给max(T=[3, 1], H=2)。它正在通过 H 作为 Max。
  • 您能解释一下原因吗?看来我不是很理解第 2 步和第 3 步。 H=2 , T=[3, 1] 当然是有道理的,但是在 -> max(T, H) 我卡住了。
【解决方案2】:

这个函数可以改写成这样:

max([H|T]) -> max(T, H).

max([], Max) -> Max;
max([H|T], Max) ->
   NewMax = if H > Max -> H;
               true -> Max
            end,
   %% NewMax = erlang:max(H, Max),
   max(T, NewMax).

要理解它,您必须知道模式匹配的工作原理。

  1. 我们采用列表的头部元素并将其视为当前最大值。我们需要查看尾部的所有其余元素,并检查它们是否更大。
  2. 如果列表的其余部分为空,则当前最大值为结果。
  3. 如果列表不为空,则获取新的头部并确定新的最大值。然后继续列表的其余部分和新的最大值。这里必须注意的是,传递给max/2 的下一次迭代的列表始终是之前传递的值的尾部,因此我们不会检查我们已经看到的值。

【讨论】:

    【解决方案3】:

    代码中的最后三行都是同一函数 (max/2) 的不同子句。这意味着无论何时调用 max 函数并传递两个参数,它将与这三个子句进行模式匹配。

    这个子句:

    max([_|T], Max) -> max(T, Max);
    

    只要列表非空且列表头 (H) 小于或等于 Max,就会匹配。它将调用max/2 传递T 这是一个列表和Max 这是一个数字。这个新调用也将与三个子句进行模式匹配。

    这个子句:

    max([], Max) -> Max.
    

    只要列表为空,就会匹配,并且只返回Max,这是一个数字。

    【讨论】:

      【解决方案4】:

      理解递归的最佳方式是将其可视化。举个很简单的例子:

      假设你想知道什么是成为美国总理的资格,即:

      你必须是美国的国民,这是规则:

      1. 您是美国(或)出生的人
      2. 您的父母是美国公民

      现在,第一个选项直接让你成为美国公民,或者同样的事情适用于你的父母,他们可能会再次检查他们的父母......等等。

      所以会有一个直截了当的答案,这里是第一个选项。这称为基本案例。在第二个选项中,您可以为您的父母应用相同的公民身份检查流程。

      这是一个非常简单的可以解释递归的伪代码:

      isEligibleForPrimeMinister checkCitizenship(You, yourParents){
                Base Case {returns true(That you are US citizen)}
                checkCitizenship(yourParents, YourGrandParents)
                }
      

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 2012-01-17
        • 2021-11-29
        • 2022-01-24
        相关资源
        最近更新 更多