リストのコピーに問題があります:
E0
から'get_Edge'
を取得した後、'E0_copy = list(E0)'
を呼び出してE0
のコピーを作成します。ここでE0_copy
はE0
のディープコピーであり、E0_copy
を'karger(E)'
に渡すと思います。しかし、メイン機能では。
forループ前の'print E0[1:10]'
の結果がforループ後の結果と異なるのはなぜですか?
以下は私のコードです:
def get_graph():
f=open('kargerMinCut.txt')
G={}
for line in f:
ints = [int(x) for x in line.split()]
G[ints[0]]=ints[1:len(ints)]
return G
def get_Edge(G):
E=[]
for i in range(1,201):
for v in G[i]:
if v>i:
E.append([i,v])
print id(E)
return E
def karger(E):
import random
count=200
while 1:
if count == 2:
break
Edge = random.randint(0,len(E)-1)
v0=E[Edge][0]
v1=E[Edge][1]
E.pop(Edge)
if v0 != v1:
count -= 1
i=0
while 1:
if i == len(E):
break
if E[i][0] == v1:
E[i][0] = v0
if E[i][1] == v1:
E[i][1] = v0
if E[i][0] == E[i][1]:
E.pop(i)
i-=1
i+=1
mincut=len(E)
return mincut
if __name__=="__main__":
import copy
G = get_graph()
results=[]
E0 = get_Edge(G)
print E0[1:10] ## this result is not equal to print2
for k in range(1,5):
E0_copy=list(E0) ## I guess here E0_coypy is a deep copy of E0
results.append(karger(E0_copy))
#print "the result is %d" %min(results)
print E0[1:10] ## this is print2
E0_copy
はディープコピーではありません。 list()
を使用してディープコピーを作成しません(list(...)
とtestList[:]
はどちらも浅いコピーです)。
リストのディープコピーには copy.deepcopy(...)
を使用します。
deepcopy(x, memo=None, _nil=[])
Deep copy operation on arbitrary Python objects.
次のスニペットを参照してください-
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b # b changes too -> Not a deepcopy.
[[1, 10, 3], [4, 5, 6]]
ここでdeepcopy
操作を参照してください
>>> import copy
>>> b = copy.deepcopy(a)
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]
>>> a[0][1] = 9
>>> a
[[1, 9, 3], [4, 5, 6]]
>>> b # b doesn't change -> Deep Copy
[[1, 10, 3], [4, 5, 6]]
多くのプログラマーがリンクリストをディープコピーするように求められる1つまたは2つのインタビューの問題に遭遇したと思いますが、この問題は思ったほど簡単ではありません!
pythonには、2つの便利な機能を持つ「コピー」というモジュールがあります
import copy
copy.copy()
copy.deepcopy()
copy()はシャローコピー関数です。指定された引数が複合データ構造、たとえばlistの場合、pythonは別のオブジェクトを作成します同じタイプ(この場合、新しいリスト)、ただし古いリスト内のすべてについて、参照のみがコピーされます
# think of it like
newList = [elem for elem in oldlist]
直観的に、deepcopy()は同じパラダイムに従うと仮定できますが、唯一の違いは、各elemに対して、deepcopyを再帰的に呼び出すことです(ちょうどmbcoderの答えのように)
しかしこれは間違っています!
deepcopy()は、元の化合物データのグラフィック構造を実際に保存します。
a = [1,2]
b = [a,a] # there's only 1 object a
c = deepcopy(b)
# check the result
c[0] is a # return False, a new object a' is created
c[0] is c[1] # return True, c is [a',a'] not [a',a'']
これはトリッキーな部分です。deepcopy()のプロセス中に、ハッシュテーブル(Pythonの辞書)を使用してマッピングします。「old_object ref on new_object ref」。これにより、不要な重複を防ぎ、コピーされた複合データの構造を保持
リストの内容がプリミティブデータ型の場合、内包表記を使用できます
new_list = [i for i in old_list]
次のような多次元リストにネストできます。
new_grid = [[i for i in row] for row in grid]
再帰的なディープコピー関数です。
def deepcopy(A):
rt = []
for elem in A:
if isinstance(elem,list):
rt.append(deepcopy(elem))
else:
rt.append(elem)
return rt
編集:Cfreakが述べたように、これは既にcopy
モジュールに実装されています。
list elements
がimmutable objects
の場合、これを使用できます。それ以外の場合は、deepcopy
モジュールのcopy
を使用する必要があります。
このようにlist
をディープコピーする最短の方法を使用することもできます。
a = [0,1,2,3,4,5,6,7,8,9,10]
b = a[:] #deep copying the list a and assigning it to b
print id(a)
20983280
print id(b)
12967208
a[2] = 20
print a
[0, 1, 20, 3, 4, 5, 6, 7, 8, 9,10]
print b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10]
リストをツリーと見なすと、Pythonのdeep_copyは次のように最もコンパクトに記述できます。
def deep_copy(x):
if not isinstance(x, list): return x
else: return map(deep_copy, x)