我在 CS61A 中遇到了问题:
给定一个唯一元素的序列,该序列的排列是一个以某种任意顺序包含序列元素的列表。例如,
、[2, 1, 3]
和[1, 3, 2]
是序列[3, 2, 1]
的一些排列。1, 2, 3]
实现
,一个生成器函数,它接受序列gen_perms
并返回一个生成seq
的所有排列的生成器。对于此问题,假设seq
不会为空。seq
可以按任何顺序产生排列。
我的解决方案是:
def gen_perms(seq):
def generator(seq_):
list_seq=list(seq_)
if len(list_seq)==1:
yield list_seq
else:
for item in generator(list_seq[1:]):
for i in range(len(list_seq)):
yield item[:i]+[list_seq[0]]+item[i:]
return generator(seq)
调用示例:
print(list(gene_perms([1, 2, 3])))
上面的代码输出了预期的结果:
[[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]
我的疑问是它看起来不应该有正确的输出。在我的代码中,
generator
是递归构建的,yield
的generator(list_seq[1:])
行出现在generator(list_seq)
之前,它应该首先产生其子序列的排列,然后才产生序列本身的排列。但前者甚至没有出现在输出中。
有人可以向我解释一下吗?也许我对发电机的工作原理有错误的理解。
尽管更深层次的递归调用的
yield
发生得更早,但这些产生的值会被进行更深层次递归调用的 for
循环所消耗。这些产生的值不会神奇地冒出整个递归树!它们由直接调用者使用,而不是由递归堆栈更高层的任何调用者使用。每个生成器执行(唯一)负责向其直接消费者产生值。递归中更深层次的调用不会产生顶级调用者将看到的值。
关于您的代码的其他备注
lists,而不是通过执行 list(seq_)
或执行
[seq[0]]
,因为:
yield
中也取一个切片来注入第一个元素,所以不是
[seq[0]]
(创建列表),而是
seq[:1]
:这也适用于字符串和元组。
yield
已经创建了一个新序列(通过使用切片和
+
运算符)。
gen_perms
即可。
def gen_perms(seq):
if not seq:
yield seq
else:
for item in gen_perms(seq[1:]):
for i in range(len(seq)):
yield item[:i] + seq[:1] + item[i:]
运行示例print(*gen_perms([1,2,3])) # list input
# -> [1, 2, 3] [2, 1, 3] [2, 3, 1] [1, 3, 2] [3, 1, 2] [3, 2, 1]
print(*gen_perms((1,2,3))) # tuple input
# -> (1, 2, 3) (2, 1, 3) (2, 3, 1) (1, 3, 2) (3, 1, 2) (3, 2, 1)
print(*gen_perms("abc")) # string input
# -> abc bac bca acb cab cba
(诚然,输入不应该是 range
实例,因为输出不能具有“排列”范围;不存在这样的事情。我假设代码挑战并不打算使用范围对象调用此函数)