如何跟踪这个递归程序

时间:2015-05-17 19:10:56

标签: python recursion

我想知道是否有人能够告诉我这个程序是如何得出正确答案的。我试图追踪它并且不确定去哪里因为它有一个or,所以我很困惑,应该如何跟踪它。谢谢你的任何澄清。

编写一个功能分区,其中包含数字xs列表,起始位置i和所需总和s并返回TrueFalse取决于是否有可能从位置i开始查找列表元素的子序列,其总和恰好为s。请注意,始终可以生成总和为0的元素的子序列,即空元素序列。

def partition(xs,i,s):
    print i,s
    if i == len(xs):
        return s == 0
    else:
        return partition(xs,i+1,s-xs[i]) or partition(xs,i+1,s)

4 个答案:

答案 0 :(得分:3)

rcviz模块是一个很好的工具,可以帮助可视化递归函数:

enter image description here

  

边缘按执行遍历它们的顺序编号。 2.边缘从黑色变为灰色,表示遍历顺序:首先是黑色边缘,最后是灰色边缘。

如果您按照编号 1-11 的电话进行操作,您可以确切地看到发生了什么,i0开始,然后转到1,2 3,最后4,左边的最后一个值是partitition([1,2,3,4],4,-2)所以它为s == 0返回False。

接下来我们回到i 2然后再回到3,4,最后回到partitition([1,2,3,4],4,1)s == 1再次False

接下来,我们从以6结尾的步骤partitition([1,2,3,4],4,5)开始,s == 0再次为假。

最后在右侧,我们从partitition([1,2,3,4],4,7)一直到partitition([1,2,3,4],4,0),其中s == 0为True,函数返回True

如果您接听前四个电话,您可以看到流程如何以及如何更改。

 partitition([1,2,3,4],1,7)  # -> xs[i] = 1 s - 1 = 7
 partitition([1,2,3,4],2,5)  # -> xs[i] = 2 s - 2 = 5
 partitition([1,2,3,4],2,5)  # -> xs[i] = 3 s - 3 = 2
 partitition([1,2,3,4],2,5)  # -> xs[i] = 4 s - 4 = -2
 s == 0 # -> False

答案 1 :(得分:2)

也许这个版本在逻辑上等同,使它更清晰一点。关键是return a or b等同于if a: return a else: return b

def partition(xs,i,s):
print i,s
if i == len(xs):
    # Base case: If the goal is to sum to 0, we succeed.
    return s == 0
else:
    # First, try including element i in our sum:
    first_try = partition(xs,i+1,s-xs[i])
    if first_try:
        return True
    else:
        # If first try failed, try not including element i
        second_try = partition(xs,i+1,s)
        return second_try

答案 2 :(得分:0)

这是or在这种情况下如何运作的解释:

return partition(xs,i+1,s-xs[i]) or partition(xs,i+1,s)
如果此表达式的计算结果为partition(xs,i+1,s-xs[i])

将返回True。如果partition(xs,i+1,s-xs[i])评估为False,则会返回partition(xs,i+1,s)(无论评估为True还是False)。

请注意,您可以使用以下一组简单示例对此进行测试:

In [1]: 1 or 2  # When both are True, the first is returned.
Out[1]: 1

In [2]: 0 or 2  # When the first is False, the second is returned.
Out[2]: 2

In [4]: 0 or False  # When both are False, the second is returned.
Out[4]: False

答案 3 :(得分:0)

我认为如果用更好的名字和没有索引编写它会变得容易多了:

def can_add_to(numbers, sumwanted):
    if not numbers:
        return sumwanted == 0
    first, *rest = numbers
    return can_add_to(rest, sumwanted-first) or can_add_to(rest, sumwanted)

print(can_add_to([1, 4, 9, 25], 13))

这和你的一样,只是更具可读性。然后说明:

如果没有数字,那么答案是"是"当且仅当所需金额为零时,我们可以马上说出来。

否则取第一个数字(和其余数字)。您可以将它用于总和。

使用它:can_add_to(rest, sumwanted-first)告诉您剩余总和(减去first之后)是否可以从其余数字中获得。

不使用它:can_add_to(rest, sumwanted-first)告诉您整个总和是否可以仅由其余数字构成。

总体答案是"是"当且仅当您可以使用 > first来计算总和。这就是为什么你把两个子答案和or放在一起的原因。