因为您要修改的其中一个项是另一个项的属性,所以这些项并不是相互独立的——需要一个序列化顺序来确定操作将要执行的操作,并且该操作是从左到右的。
给出了以下共同的序曲:
old_nodeA = nodeA
old_nodeB = nodeB
old_nodeA_next = nodeA.next
工作代码类似于以下代码:
nodeB = old_nodeA
nodeA.next = old_nodeB
nodeA = old_nodeA_next
这是坏的一个:
nodeB = old_nodeA
nodeA = old_nodeA_next
nodeA.next = old_nodeB
不同的是
nodeA.next
指
next
不同的属性
nodeA
让我们看看在运行时,在一切正常的情况下,这是如何实现的,一些伪代码显示了对象ID,这样您就可以区分对象在原地发生变化和引用发生变化:
# Working implementation
###############################################################
# id(nodeA) # id(nodeB) # AAA.v # AAA.next # BBB.v # BBB.next #
###############################################################
# AAA # BBB # 1 # BBB # 2 # None # Starting condition
# AAA # AAA # 1 # BBB # 2 # None # nodeB = old_nodeA
# AAA # AAA # 1 # BBB # 2 # None # nodeA.next = old_nodeB
# BBB # AAA # 1 # BBB # 2 # None # nodeA = old_nodeA_next
A
和
B
相比之下:
# Broken implementation
###############################################################
# id(nodeA) # id(nodeB) # AAA.v # AAA.next # BBB.v # BBB.next #
###############################################################
# AAA # BBB # 1 # BBB # 2 # None # Starting condition
# AAA # AAA # 1 # BBB # 2 # None # nodeB = old_nodeA
# BBB # AAA # 1 # BBB # 2 # None # nodeA = old_nodeA_next
# BBB # AAA # 1 # BBB # 2 # BBB # nodeA.next = old_nodeB
当我们到达的时候
nodeA.next = old_nodeB
,名称
已经分配了最初与节点B关联的id(
BBB
起初的
节点B
下一个
指向自身的指针,生成问题核心的循环。