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

After shifting values in linked list. Changing values in the head alters 2 nodes at once

描述

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

下面是我 运行 移位值和更新头部的代码后发生的情况。 头部是table.

的第一行

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

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

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

此外,如果我更新第 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

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

我不完全确定我是否理解发生了什么。但我怀疑复制数据时出现问题。请注意,在 Python 中,如果您将变量设置为另一个对象 (class),则它是按引用传递的,而不是按值传递的。

例如:

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

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

不仅 classes 通过引用传递,而且列表也是如此。好像你是上一个节点到下一个节点的passing/setting data(我认为是列表?)。您不是在复制数据的内容,而是传递对此 data 列表的引用。这可能会导致您看到的行为。您可以通过使用 copy() 或对列表进行切片来缓解这种情况。例如:

b = a.copy()

new_l = l[:]

另外,请参阅有关复制对象的 Python FAQ

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

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

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

 oldvalue = self.linkedlist.head.data

与:

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

然后就可以了