在多次分配的退化情况下会发生什么?

时间:2016-01-19 16:49:40

标签: python

teaching myself algorithms。我需要在列表中交换两个项目。 Python使一切变得简单:

def swap(A, i, j):
    A[i], A[j] = A[j], A[i]

这是一种享受:

>>> A = list(range(5))
>>> A
[0, 1, 2, 3, 4]
>>> swap(A, 0, 1)
>>> A
[1, 0, 2, 3, 4]

请注意,该函数对退化情况i = j具有弹性。正如您所期望的那样,它只会使列表保持不变:

>>> A = list(range(5))
>>> swap(A, 0, 0)
>>> A
[0, 1, 2, 3, 4]

后来我想在列表中置换三个项目。我写了一个函数来在3个循环中置换它们:

def cycle(A, i, j, k):
    A[i], A[j], A[k] = A[j], A[k], A[i]

这很有效:

>>> A = list("tap")
>>> A
['t', 'a', 'p']
>>> cycle(A, 0, 1, 2)
>>> A
['a', 'p', 't']

然而,我(最终)发现它在堕落的情况下出错了。我假设一个退化的3周期将是一个交换。这是i = jcycle(i, i, k) ≡ swap(i, k)

的时间
>>> A = list(range(5))
>>> cycle(A, 0, 0, 1)
>>> A
[1, 0, 2, 3, 4]

但当i = k发生其他事情时:

>>> A = list(range(5))
>>> sum(A)
10
>>> cycle(A, 1, 0, 1)
>>> A
[1, 1, 2, 3, 4]
>>> sum(A)
11

发生了什么? sum在任何排列下都应该是不变的!为什么这种情况i = k退化的方式不同?

我怎样才能实现我想要的目标?这是一个3周期函数,如果只有2个索引是不同的cycle(i, i, j) ≡ cycle(i, j, i) ≡ cycle(i, j, j) ≡ swap(i, j)

,则退化为交换

3 个答案:

答案 0 :(得分:23)

cycle正在按照你的要求行事:指定左手值右手值。

def cycle(A, i, j, k):
    A[i], A[j], A[k] = A[j], A[k], A[i]

在功能上等同于

def cycle(A, i, j, k):
    new_values = A[j], A[k], A[i]
    A[i], A[j], A[k] = new_values

所以当你cycle(A, 1, 0, 1)做你想说的是你想要的时候

A[1] = previous_A[0]
A[0] = previous_A[1]
A[1] = previous_A[1]

如果你想让循环按顺序工作,那么你必须按顺序编写它,否则python会评估右手,然后将其扩展到左边的参数。

答案 1 :(得分:11)

似乎你正在重新分配到同一目标 A[1],以获得呼叫的可视化:

A[1], A[0], A[1] = A[0], A[1], A[1]

请记住,来自 assignment statements

的文档
  

赋值语句评估表达式列表(请记住,这可以是单个表达式或以逗号分隔的列表,后者产生元组)并且将单个结果对象分配给每个目标列表,从左到右。

所以你的评价就像dis:

  • 创建值为A[0], A[1], A[1]的元组,转换为(0, 1, 1)
  • 从左到右将这些内容分配到目标列表A[1], A[0], A[1]

从左到右分配:

  1. A[1] = 0
  2. A[0] = 1
  3. A[1] = 1
  4. 所以第一个作业是A[1],第一个元素是元组0,第二个作业是A[0]第二个元素1,最后是最后,使用元组中的第三个元素 A[1]覆盖1

    您可以使用 dis.dis 获得更多错综复杂的视图。注意如何首先加载赋值语句右边的所有元素,然后将它们分配给它们的值:

    dis.dis(cycle)
      2           0 LOAD_FAST                0 (A)
                  3 LOAD_FAST                2 (j)
                  6 BINARY_SUBSCR
                  7 LOAD_FAST                0 (A)
                 10 LOAD_FAST                3 (k)
                 13 BINARY_SUBSCR
                 14 LOAD_FAST                0 (A)
                 17 LOAD_FAST                1 (i)
                 20 BINARY_SUBSCR                   # Loading Done
                 21 ROT_THREE
                 22 ROT_TWO
                 23 LOAD_FAST                0 (A)  # Assign first
                 26 LOAD_FAST                1 (i)
                 29 STORE_SUBSCR
                 30 LOAD_FAST                0 (A)  # Assign second
                 33 LOAD_FAST                2 (j)
                 36 STORE_SUBSCR
                 37 LOAD_FAST                0 (A)  # Assing third
                 40 LOAD_FAST                3 (k)
                 43 STORE_SUBSCR
                 44 LOAD_CONST               0 (None)
                 47 RETURN_VALUE
    

答案 2 :(得分:3)

由于cycle(A, 1, 0, 1)变为A[1], A[0], A[1] = A[0], A[1], A[1],导致A[0]A[1]A[1]的旧值结束。 cycle(0, 0, 1)有效,因为它变为A[0], A[0], A[1] = A[0], A[1], A[0],相当于swap(A, k, j)