Python递归函数参数问题

Posted

技术标签:

【中文标题】Python递归函数参数问题【英文标题】:Python recursion function parameters issue 【发布时间】:2022-01-07 16:22:14 【问题描述】:

我在内部多次调用一个函数来解决子集和问题,使用它所调用的递归解决方案;无论如何,我无法弄清楚为什么 n (这是数组的元素数)值一开始会减少,直到它达到 0,这就是我得到它,但是,在它本身再次调用它之后,它使 n 值递增。为什么会发生这种情况,因为整个函数甚至对 n 值都没有增量贡献? n 的递增值从何而来?

代码如下:

def printAllSubsetsRec(arr, n, currentSubset, sum):
    # If remaining sum is 0, then print all
    # elements of current subset.

    if (sum == 0):
        i = 0
        sumOfValue = 0
        for value in currentSubset:
            i += 1
            sumOfValue += value
            if (i == len(currentSubset)):
                print(value, " = ", sumOfValue)
            else:
                print(value, end=" + ")
        return True

    # If there are no elements in the array and the sum is not equal to 0.
    if (n == 0 and sum != 0):
        return None


    # I consider two cases for every element:
    # a) Excluding last element.
    # b) Including last element in current subset.
    # -------------------------------------------------

    # Excluding the last element:
    printAllSubsetsRec(arr, n - 1, currentSubset, sum)

    v = [] + currentSubset
    v.append(arr[n - 1])

    # Including the last element:
    printAllSubsetsRec(arr, n - 1, v, sum - arr[n - 1])


#Main:
arr = [10, 7, 5, 18, 12, 20, 15]
sum = 35
n = len(arr)
currentSubset = []
printAllSubsetsRec(arr, n, currentSubset, sum)

输出应该是:

18 + 7 + 10 = 35

12 + 18 + 5 = 35

20 + 5 + 10 = 35

15 + 20 = 35

提前致谢!

【问题讨论】:

您看到了在同一个函数中进行两次递归调用的效果。其中第一个被调用,导致 n 减少并建立一个递归调用堆栈。这种情况一直持续到您返回为止。此时堆栈展开一层,现在发生第二次递归调用。 “n”的值增加了,因为仍然有一堆调用保留了它们原来的“n”。 我猜这只是递归的一种常见性质,除非递归结构是线性的。考虑一个递归问题,以获得为了逃离迷宫而必须采取的步骤数。当您在迷宫中蜿蜒前行时,您通常会增加步数,但是一旦您遇到死胡同,您就会回到前一个岔路口,就像您减少 n。但实际上它只是回到原始调用堆栈并尝试另一条路径(n 减少)。 顺便说一下,不要使用名称sum,因为它会覆盖内置函数。 谢谢你们,我明白了! 【参考方案1】:

递归是一种函数式遗产,因此将其与函数式风格一起使用会产生最佳效果。这意味着要避免诸如突变、变量重新分配和其他副作用之类的事情 -

逻辑if 没有对应的else isumOfValue 的突变和重新分配 像print这样的副作用

递归不一定是困难或痛苦的。使用功能学科,我们可以编写 subsets(t,n) 和 inductive reasoning -

    如果目标和 n 为零,则产生空解 (感应)否则n 为负或正。如果n 为负数或输入数组t 为空,则我们越界。停止迭代。 (感应)n 是正的,t 至少有一个元素。对于子问题(t[1:],n-t[0]) 的所有s,在t[0] 前面加上s 并屈服。 并且产生子问题(t[1:],n)的所有结果
def subsets(t, n):
  if n == 0:
    yield ()                              #1
  elif n < 0 or not t:
    return                                #2
  else:
    for s in subsets(t[1:], n - t[0]):    #3
      yield (t[0], *s)
    yield from subsets(t[1:], n)
for s in subsets([10, 7, 5, 18, 12, 20, 15], 35):
  print(s)
(10, 7, 18)
(10, 5, 20)
(5, 18, 12)
(20, 15)

通知-

所有操作都不会改变或重新分配变量 像print 这样的副作用被换成yield 调用者可以随意使用和转换结果

将结果格式化为数学表达式 -

for s in subsets([10, 7, 5, 18, 12, 20, 15], 35):
  print(" + ".join(map(str, s)), "=", 35)
10 + 7 + 18 = 35
10 + 5 + 20 = 35
5 + 18 + 12 = 35
20 + 15 = 35

要将生成器的所有输出收集到一个列表中,请使用list -

print(list(subsets([10, 7, 5, 18, 12, 20, 15], 35)))
[(10, 7, 18), (10, 5, 20), (5, 18, 12), (20, 15)]

【讨论】:

哇,太棒了!这真的是专业的干净代码!谢谢!

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

python 基础 11 带参数装饰器与递归函数

Python函数基础学习(定义函数参数递归函数)

python 复习 4-1 函数参数返回值递归

Python的函数参数和递归参数

Python基础笔记:函数:调用函数定义函数函数的参数递归函数

python小功能-递归解析Json