在链表中移动值之后。更改头部中的值会同时更改 2 个节点

Posted

技术标签:

【中文标题】在链表中移动值之后。更改头部中的值会同时更改 2 个节点【英文标题】:After shifting values in linked list. Changing values in the head alters 2 nodes at once 【发布时间】:2022-01-22 19:18:13 【问题描述】:

说明

所以我决定使用 PyGame 在 Python 中制作一个蛇游戏。为了好玩,我决定使用链表来表示蛇。最初我认为要移动蛇,我必须将每个值移向头节点的新目标位置,然后用它的新目标更新头节点。我很快意识到这种方法过于复杂且不必要。然而,在我尝试通过将链表中的所有值移向头部并随后用它的新值更新头部来实现它时,我最终破坏了我的链表。

这是在我运行代码以移动值并更新磁头后发生的情况。 头部是表格的第一行。

链表中数据的原始打印输出

x y
100 50
90 50
80 50
70 50

移位后的数据打印输出

x y
100 50
100 50
90 50
80 50

这就是我们想要的。每一行都已正确移动。所有需要做的就是更新头部。在这种情况下,蛇正在上升,间隔为 10,因此我们将头部中的 y 更新 10。完成后会发生这种情况。

x y
100 60
100 60
90 50
80 50

当更新头部中的数据时,下一个节点现在也同时更新。如果我在移动数据后尝试以相同的方式更新第二个节点,也会发生同样的事情。如果我在改变值之前尝试这样做,一切正常,所以当我改变值时似乎发生了一些事情。我通过 print(node) 检查了每个节点的内存地址,它们都是不同的。

另外,如果我更新第 3 或第 4 个节点的数据属性,它可以正常工作,而其他节点则保持不变。所以这只是移位后第一个和第二个节点的特征。

这是我为移动列表中的值而编写的代码

    def Move(self, direction):
        if(direction == 'UP'):
            
            oldvalue = self.linkedlist.head.data

            tempnode = self.linkedlist.head
            tempv = None
            while(tempnode.nextnode is not None):
                tempnode = tempnode.nextnode
                tempv = tempnode.data
                tempnode.data = oldvalue
                oldvalue = tempv

            self.linkedlist.printList()
            
        self.linkedlist.head.data[1] += 10

如果这很难理解,我只需使用 2 个临时变量来存储当前节点中的数据和前一个节点中的数据。用之前的节点数据更新下一个节点,然后将当前节点的数据再次存储在 tempv 中。

以防万一我将在下面提供我的链表实现的代码。

from Node import Node

class LinkedList:
    def __init__(self):
        self.head = None

    def printList(self):
        
        printnode = self.head

        while(printnode is not None):
            print(f'printnode.data')
            printnode = printnode.nextnode
        print('')
class Node:
    def __init__(self, data = None):
        self.data = data
        self.nextnode = None

感谢您的帮助,如果解决方案很简单,我深表歉意。我盯着看了几个小时,也试图找到类似的帖子,但无济于事。

【问题讨论】:

【参考方案1】:

我不完全确定我是否理解正在发生的事情。但我怀疑复制数据时出现问题。请注意,在 Python 中,如果你将一个变量设置为另一个对象(类),它是通过引用而不是值传递的。

例如:

class ExampleClass:
    def __init__(self, value):
        self.value = value

A = ExampleClass(5)
B = A
B.value = 3
print(A.value) # prints 3

不仅类是通过引用传递的,列表也是如此。似乎您正在将前一个节点的 data (我认为是一个列表?)传递/设置到下一个节点。您不是在复制数据的内容,而是传递对此data 列表的引用。这可能会导致您看到的行为。您可以通过使用copy() 或切片列表来缓解这种情况。例如:

b = a.copy()

new_l = l[:]

另外,请参阅Python FAQ 复制对象。

【讨论】:

我怀疑这可能与复制和我正在使用的参考有关。我觉得你的描述就是这样!我不知道 Python 的 copy() 方法,也不担心对象是通过引用传递的。我会调查一下,这看起来将是公认的答案。谢谢你,非常感谢这些例子。 @Fijistreams 让我知道它是否不起作用,然后我再看看。 ;-)【参考方案2】:

由于您将数据从头节点复制(“转移”)到其后继节点,因此它们都具有对相同数据的引用。因此,对该数据的任何操作都将在两个节点中可见。

这不会发生在其他节点上,因为源节点(从中复制数据)本身会从其前任节点获取值,因此在这种情况下,没有两个节点共享相同的数据。但是头节点没有从它的前任那里得到数据,因为……它没有前任。

因此,您需要根据从头节点读取的数据创建一个新的数据列表。您可以通过替换来做到这一点:

 oldvalue = self.linkedlist.head.data

与:

 oldvalue = self.linkedlist.head.data[:]

然后就可以了。

【讨论】:

以上是关于在链表中移动值之后。更改头部中的值会同时更改 2 个节点的主要内容,如果未能解决你的问题,请参考以下文章

用[(NgModel)]更改绑定的Angular表中的值会影响其他字段

装箱拆箱

通过检查元素更改隐藏字段的值会更改服务器端的实际值

javascript中在链表中向前(向后)移动n个节点

从装箱拆箱看泛型

在链表中递归插入节点,给定位置和值