我正在阅读这篇文章,试图了解有关排列的更多信息:Finding all possible permutations of a given string in python
我卡在这段代码上了:
def permutations(string, step = 0):
# if we've gotten to the end, print the permutation
if step == len(string):
print "".join(string)
# everything to the right of step has not been swapped yet
for i in range(step, len(string)):
# copy the string (store as array)
string_copy = [character for character in string]
# swap the current index with the step
string_copy[step], string_copy[i] = string_copy[i], string_copy[step]
# recurse on the portion of the string that has not been swapped yet (now it's index will begin with step + 1)
permutations(string_copy, step + 1)
我不明白我们将当前索引与步骤交换的行,这到底是做什么的?我知道我们向右移动一次 step 但是 string_copy[step], string_copy[i] = string_copy[i], string_copy[step] 是如何做到这一点的呢?我只是不知道发生了什么
请您参考如下方法:
a,b = b,a 是交换两个值的 Python 习语,也可以写成:
temp = a
a = b
b = temp
在 for 循环内,在 permutations(...) 之上,添加这一行:
print "step", step, "index", i, string, "->", string_copy
现在它将向您展示它运行时的内部工作原理:
>>> permutations("abc")
step 0 index 0 abc -> ['a', 'b', 'c']
step 1 index 1 ['a', 'b', 'c'] -> ['a', 'b', 'c']
step 2 index 2 ['a', 'b', 'c'] -> ['a', 'b', 'c']
abc
step 1 index 2 ['a', 'b', 'c'] -> ['a', 'c', 'b']
step 2 index 2 ['a', 'c', 'b'] -> ['a', 'c', 'b']
acb
step 0 index 1 abc -> ['b', 'a', 'c']
step 1 index 1 ['b', 'a', 'c'] -> ['b', 'a', 'c']
step 2 index 2 ['b', 'a', 'c'] -> ['b', 'a', 'c']
bac
step 1 index 2 ['b', 'a', 'c'] -> ['b', 'c', 'a']
step 2 index 2 ['b', 'c', 'a'] -> ['b', 'c', 'a']
bca
step 0 index 2 abc -> ['c', 'b', 'a']
step 1 index 1 ['c', 'b', 'a'] -> ['c', 'b', 'a']
step 2 index 2 ['c', 'b', 'a'] -> ['c', 'b', 'a']
cba
step 1 index 2 ['c', 'b', 'a'] -> ['c', 'a', 'b']
step 2 index 2 ['c', 'a', 'b'] -> ['c', 'a', 'b']
cab
- 看看只要步骤和索引相同,一个字符就会与其自身交换,没有任何变化。所以有十五次调用生成六种排列。
我发现很难举出一个更清晰的例子。这个怎么样:
# (step, index)
(0, 0) -- a
(1, 1) -- ab
(2, 2) -- abc # reached the last character, print this!
<-
(1, 2) -- ac
(2, 2) -- acb # reached the last character, print this!
<-
<-
(0, 1) -- b
(1, 1) -- ba
(2, 2) -- bac # reached the last character, print this!
<-
(1, 2) -- bc
(2, 2) -- bca # reached the last character, print this!
<-
<-
(0, 2) -- c
(1, 1) -- cb
(2, 2) -- cba # reached the last character, print this!
<-
(1, 2) -- ca
(2, 2) -- cab # reached the last character, print this!
<-
<-
- 这不仅显示了一个循环,还显示了一个层次结构,一棵树。右边的东西更深,它们在左边的东西下面。在他们下面。在他们里面。模式的第一部分是
--a下的所有东西,第二部分是--b下的所有东西,第三部分是-- c下的所有内容。 - 每次调用 permute() 都会将所有内容 -> 推到右边。
- 每次 permute() 完成时,我们返回 <- 到左边。
- 向右移动会增加步数。
- 在同一缩进处向下移动会增加索引。
- 向下和向右移动,同时增加 step 和 index。
- 每次我们缩进 -> 我们从父事物中获取状态。
--a下的所有内容都以--a开头。-- ab下的所有内容都以-- ab开头。 - 缩进有 3 个左右位置,因为字符串有 3 个字符,4 个字符的字符串有另一个级别的缩进,因此有更多的行 - 用于更多的排列。
- “步骤”数字与缩进的正确程度相匹配并非巧合。
并且,尝试回答您的评论问题:
for i in range(step, len(string)):行从当前缩进/步进级别开始索引计数器。这就是它从 (1,1) 到 (2,2) 更深层次的原因。您可以看到,当我们从 (2,2) 返回时,我们选择了之前的状态 (1,1) 并在相同级别转到 (1,2),然后进入 (2, 2) 在更深的之下。我们从 (2,2) 回到 (0,0) 的原因是因为我们通过向右缩进尽可能多的次数到达字符串的末尾,直到我们已用完以“a”开头的排列。 'abc' 和 'acb' 然后我们回到开头,从 'b' 开始。 'bac' 和 'bca'。然后我们用完了,回到起点。
例如
(0, 0) -- a
(1, 1) -- ab
(2, 2) -- abc #STEP has reached the end of the string, move left
# We moved left, index was 1 so we've got more work to do
(1, 2) -- ac
(2, 2) -- acb #STEP has reached the end of the string, move left
# We moved left, index was 2 so that has also reached the end of the string
# no more work to do inside the group (0,0) -- a, so move left again.
<-
# Now at this far left level, we can change the far left column from (0,0) to (0,1)
# and then repeat all of the above.
在每个级别,都在发生相同的模式。更改此列/级别,并重复所有较低级别。这是一种自相似、递归、循环的模式。
我的示例代码中有 8 个版本的 print 语句,打印不同的事物组合以尝试显示正在发生的事情。我认为以上是最清楚的,但我鼓励您放入打印语句并重新运行它。在交换前后打印'string'和'string_copy',打印'string_copy[step:]'并打印""*(3*(step+1))打印缩进。
据我所知没有简单的解释。没有什么可以替代盯着代码,一点一点地一遍又一遍地研究它,直到它更有意义。
