【问题标题】:Recursion in Python 3.2Python 3.2 中的递归
【发布时间】:2012-11-24 03:10:37
【问题描述】:

我正试图围绕递归展开我的头脑,并发布了一个工作算法来生成给定列表的所有子集。

def genSubsets(L):
    res = []
    if len(L) == 0:
        return [[]]
    smaller = genSubsets(L[:-1])
    extra = L[-1:]
    new = []
    for i in smaller:
        new.append(i+extra)
    return smaller + new

假设我的列表是 L = [0,1],正确的输出是 [[],[0],[1],[0,1]]

使用打印语句,我缩小了在进入 for 循环之前两次调用 genSubsets 的范围。我得到了这么多。

但是为什么第一个 for 循环初始化 L 的值只是 [0] 而第二个 for 循环使用 [0,1]?包含 for 循环的递归调用究竟是如何工作的?

【问题讨论】:

  • 您可以使用this 来查找代码流。
  • 感谢西比!太棒了!

标签: python list recursion python-3.x


【解决方案1】:

我不太喜欢尝试可视化递归函数的整个调用图以了解它们的作用。

我相信有一个更更简单的方法:

进入童话世界,递归函数在其中做正确的事™。

假设genSubsets(L) 有效:

# This computes the powerset of the list L minus the last element
smaller = genSubsets(L[:-1])

因为这很神奇,所以唯一缺少的条目是那些包含最后一个元素的条目。

这个片段构建了所有那些缺失的子集:

new = []
for i in smaller:
    new.append(i+extra)

现在我们有那些子集包含new 中的最后一个元素,而我们有那些子集包含smaller 中的最后一个元素。

因此我们现在必须拥有所有子集,因此我们可以返回 new + smaller

唯一剩下的就是基本情况,以确保递归停止。因为空集(或本例中的列表)是每个幂集的一个元素,我们可以使用它来停止递归:请求空集的幂集是包含空集的集合。所以我们的基本情况是正确的。由于每个递归步骤都会从列表中删除一个元素,因此必须在某个时间遇到基本情况

因此,代码确实会产生幂集。

注意:这背后的原理是归纳法。如果某样东西适用于某个已知的n0,我们可以证明:适用于n 的算法意味着它适用于n+1,因此它必须适用于所有人n ≥ n0.

【讨论】:

    【解决方案2】:

    我认为使用更长的源列表实际上会更容易可视化。如果您使用[0, 1, 2],您会看到递归调用反复切断列表中的最后一项。也就是说,recusion 会构建一堆递归调用,如下所示:

    genSubsets([0,1,2])
        genSubsets([0,1])
            genSubsets([0])
                genSubsets([])
    

    此时它达到了递归算法的“基本情况”。对于此函数,基本情况是作为参数给出的列表为空时。命中基本情况意味着它返回一个包含空列表[[]] 的列表。以下是堆栈返回时的样子:

    genSubsets([0,1,2])
        genSubsets([0,1])
            genSubsets([0]) <- gets [[]] returned to it
    

    这样返回值就会回到上一级,保存在smaller 变量中。变量 extra 被分配为一个切片,其中仅包含列表的最后一项,在本例中是整个内容,[0]

    现在,循环遍历smaller 中的值,并将它们与extra 的连接添加到new。由于smaller(空列表)中只有一个值,new 最终也只有一个值,[]+[0],即[0]。我假设这是您在某个时候打印出来的值。

    那么最后一条语句返回smallernew的串联,所以返回值为[[],[0]]。堆栈的另一个视图:

    genSubsets([0,1,2])
        genSubsets([0,1]) <- gets [[],[0]] returned to it
    

    返回值再次分配给smallerextra[1],循环再次发生。这一次,new 得到两个值,[1][0,1]。它们再次连接到smaller 的末尾,返回值为[[],[0],[1],[0,1]]。最后一个堆栈视图:

    genSubsets([0,1,2]) <- gets [[],[0],[1],[0,1]] returned to it
    

    同样的事情再次发生,这次将2s 添加到到目前为止找到的每个项目的末尾。 new[[2],[0,2],[1,2],[0,1,2]] 结尾。

    最终返回值为[[],[0],[1],[0,1],[2],[0,2],[1,2],[0,1,2]]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-02
      • 2013-12-11
      • 2016-02-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多