Python 使用幂集示例理解递归

Python 使用幂集示例理解递归,python,algorithm,recursion,data-structures,Python,Algorithm,Recursion,Data Structures,我编写了一段简单的代码,使用递归打印集合的所有子集。我很难理解输出。例如,输出中的第一行显示一个空集和一个3的单例,而我希望打印一个空集和一个1的单例,然后是一个空集、一个1的单例、一个2的单例等等。然而,这不是打印的内容。我不知道如何可视化递归树。是否有任何通用技术来完成可视化?我试着画一棵树,但很快就弄糊涂了 def subsets(self, nums): inp = nums out = [] result=[] def h

我编写了一段简单的代码,使用递归打印集合的所有子集。我很难理解输出。例如,输出中的第一行显示一个空集和一个3的单例,而我希望打印一个空集和一个1的单例,然后是一个空集、一个1的单例、一个2的单例等等。然而,这不是打印的内容。我不知道如何可视化递归树。是否有任何通用技术来完成可视化?我试着画一棵树,但很快就弄糊涂了

def subsets(self, nums):
        inp = nums
        out = []
        result=[]
        def helper(inp,out,index):
            if index==len(inp):
                result.append(out)
                return
            helper(inp,out,index+1)
            helper(inp,out+[inp[index]],index+1)
            print(result)
        helper(inp,out,0)
        return result

输入“[1,2,3]”的print语句的输出如下所示

[[], [3]]
[[], [3], [2], [2, 3]]
[[], [3], [2], [2, 3]]
[[], [3], [2], [2, 3], [1], [1, 3]]
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]

如果在函数中添加一个“缩进”参数,在探索该参数的同时,您可以立即看到哪个函数调用哪个函数:

def子集(nums):
inp=nums
out=[]
结果=[]
def辅助工具(缩进、输入、输出、索引):
打印(f“{indent}->helper({inp},{out},{index})”)
如果索引==len(inp):
结果。追加(输出)
返回
辅助对象(缩进+'--',输入,输出,索引+1)
辅助对象(缩进+'--',输入,输出+[inp[index]],索引+1)
助手(“”,输入,输出,0)
返回结果
结果如下所示:

->helper([1, 2, 3],[],0)
--->helper([1, 2, 3],[],1)
----->helper([1, 2, 3],[],2)
------->helper([1, 2, 3],[],3)
------->helper([1, 2, 3],[3],3)
----->helper([1, 2, 3],[2],2)
------->helper([1, 2, 3],[2],3)
------->helper([1, 2, 3],[2, 3],3)
--->helper([1, 2, 3],[1],1)
----->helper([1, 2, 3],[1],2)
------->helper([1, 2, 3],[1],3)
------->helper([1, 2, 3],[1, 3],3)
----->helper([1, 2, 3],[1, 2],2)
------->helper([1, 2, 3],[1, 2],3)
------->helper([1, 2, 3],[1, 2, 3],3)
因此,您可以立即看到为什么首先得到[]——当您在结果中不包含任何内容的情况下遍历列表时,就会得到它。下一步是[3],因为您回溯到呼叫,在呼叫中添加3,然后转到末尾。通过进一步回溯得到[2],在输出中包含2,然后沿着不添加3的路径。然后你得到[2,3],因为你回溯一个级别,到结果中包含2的调用,这一次转到添加3的路径

不过,这可能不是计算幂集的最简单方法。大小为n的功率集与介于0和2**n-1之间的二进制数之间存在一对一的对应关系。对于每个数字,1位表示要在集合中包括哪些元素。因此,您也可以这样计算功率集:

def子集(nums):
返回[
[nums[j]表示枚举中的j,b(反转(格式(i,'b')),如果b=='1']
对于范围内的i(2**len(nums))
]

它以指数大小运行,但递归版本也是如此,当输出的大小与输入的大小成指数关系时,这是不可避免的。

如果您也包含了导致包含输出的输入,这会很有帮助。例如,更改函数开头的打印位置和/或添加额外的打印这是否回答了您的问题?使用调试器单步执行程序应该可以相当快地解决这个问题哇,这非常有用。非常感谢@福姆惠纳,欢迎你。