Python:list append函数的奇怪行为

时间:2015-03-25 07:52:05

标签: python list

我是Python的新手。

我尝试制作一个Kruskal算法。这是我的代码:

#c={('v','a'):5,('v','g'):5,('g','a'):5,('v','b'):7,('v','e'):4,('f','e'):8,('f','b'):8,('f','c'):11,('c','e'):9,('c','d'):7,('c','b'):9,('e','d'):8}
#n=8

def argmin(c):
    m=1e100
    r=()
    for i in c:
       if c[i]<m:
           m=c[i]
           r=i
    return r

def kruskal (n, c):
    T=[]
    B=[]
    while len(T)<n-1:
        E=argmin(c)
        c.pop(E)
        e=[]
        e+=E
        a0=0
        a1=0
        f0=-1
        f1=-1
        cross=0
#        print('e avant',e)
        for i in range(len(B)):
            for j in range(len(B[i])):
                if e[0]==B[i][j]:
                    cross+=1
                    f0=i   
                if e[1]==B[i][j]:
                    cross+=1
                    f1=i                        
            if cross==2: break
            else: cross=0
        if cross==2: continue
#        print('e apres',e)
        T.append(e)
#        print('T',T)
        if f0!=-1 and f1!=-1:
            B[f0].extend(B[f1])
            B.pop(f1)
        elif f0!=-1:
            B[f0].extend(e[1])
        elif f1!=-1:
            B[f1].extend(e[0])
        else :
            B.append(e)        
#        print('B', B)                
    return T

我遇到的问题是:&#34; T.append(e)&#34; 在结果中,T [0]不是我所期望的。 如果我输入以下内容:

c={('v','a'):5,('v','g'):5,('g','a'):5,('v','b'):7,('v','e'):4,('f','e'):8,('f','b'):8,('f','c'):11,('c','e'):9,('c','d'):7,('c','b'):9,('e','d'):8}

n=8

然后我调用我的函数: kruskal(8,c) 我明白了:

[['v', 'e', 'g', 'a', 'b', 'f', 'c', 'd'], ['v', 'g'], ['v', 'a'], ['v', 'b'], ['c', 'd'], ['f', 'b'], ['e', 'd']]

我期望以下内容:

[['v', 'e'], ['v', 'g'], ['v', 'a'], ['v', 'b'], ['c', 'd'], ['f', 'b'], ['e', 'd']]

2 个答案:

答案 0 :(得分:1)

没有找到你的所有代码。但是有些东西被发现,你有时会追加references list。所以只需要修复:

from copy import deepcopy

T.append(deepcopy(e)) #in place of T.append(e)

将输出

[['v', 'e'], ['g', 'a'], ['v', 'a'], ['v', 'b'], ['c', 'd'], ['f', 'b'], ['e', 'd']]

示例

a = [1, 2]
b = a
b.append(3)

>>>a
[1,2,3]

>>>b
[1,2,3]

这里发生了什么

a = [1,2]
b = a

>>>id(a), id(b)
(140526873334272, 140526873334272)

列表[1,2]taggeda两个变量b组成。因此,对列表的任何更改都会影响标记到它的每个varables

答案 1 :(得分:0)

The answer by itzmeontv关于问题的根本原因是正确的T的第一个成员是一个可变列表,然后您可以在代码中进一步修改。在您的情况下发生这种情况的代码路径有点复杂:

  1. 在您的算法的第一次迭代中,您将e追加到T - 因此T[0]引用此时的列表名称e(内容['v','e'] })
  2. 在同一次迭代中,你总是点击这个块:

     else :
         B.append(e)
    
  3. 这意味着B[0]现在也引用了名为e的列表 - 即T[0]引用与<{1}中的相同的列表 B[0]的任何更改都会反映在B[0]中,因为列表是可变的。
  4. 然后下一次迭代会创建一个新的T[0] - ,但 e中引用的列表和B[0]仍然是同一个列表,即{{1} }
  5. 然后在T[0]为零的情况下执行['v','e']时继续扩展此列表
  6. 这是在Python中分配不复制的列表的一种症状,如果您想加深理解,则会给出详细的处理in this question。有关如何将列表附加到B[f0].extend(B[f1]) is given以及timings的一系列选项 - 例如,您可能喜欢编写f0,并使用切片表示法隐式制作<{1}}的副本,在您追加它的位置。

    您可能需要考虑的一件事是,T成员加入T.append(e[:])后是否需要e成员mutable。如果你不这样做 - 一个选择可能是追加T而不是T - 即。

    tuples