指向链接列表的指针何时会更改实际列表?

我有一个单链列表L,并创建一个指向此列表P的指针。似乎有时修改P会更改实际列表,而有时修改P不会对实际列表L起作用,只会更改P指向。

假设我创建了一个指向L的指针,P = L(在python中)。进行类似P = P.next的操作会使L保持不变,但是P.next = P.next.next会改变L。类似地,通过修改P.data来更改存储在列表中的实际数据实际上会更改L.data。

为什么会这样?我觉得我缺少关于指针/引用的一些基本知识。

class Node:
    def __init__(self,val):
        self.val = val
        self.next = None

    def addNode(self,val):
        root = self
        while root.next is not None:
            root = root.next
        root.next = Node(val)

    def iterateLL(self):
        root = self
        print
        while root is not None:
            print(str(root.val) + " ",end="")
            root = root.next
        print()

if __name__ =="__main__":
    L = Node(1)
    L.addNode(2)
    L.addNode(3)
    L.addNode(4)

    # iterate through list and print:
    L.iterateLL()

    # changing value of pointer does not affect L
    P = L
    P = P.next
    L.iterateLL() # L is unchanged

    # changing "next" value of pointer does affect L
    P = L 
    P.next = P.next.next
    L.iterateLL() # now we've skipped node 2

    # changing data of pointer does affect L
    P = L
    P.val = 10
    L.iterateLL()

以上代码以以下输出执行(第一行显示原始链接列表,第二行显示更改指针P后列表未更改,而第三和第四行显示列表已更改)

1 2 3 4

1 2 3 4

1 3 4

10 3 4

这是怎么回事?为什么更改P不会影响L,但是更改P.next和P.val会呢?如果所有这些动作的行为都相同,则不会更改指针,或者总是更改链接列表(因此P = P.next应该通过摆脱第一个节点来修改L),还是从不更改链接列表(因此P.next = P.next.next应该保持L不变)?

我感觉到L.next是一个指针,就像P.next一样。因此,修改P.next最终会修改L.next指向(?)的内容。但是我觉得规则不清楚。

yddzipper 回答:指向链接列表的指针何时会更改实际列表?

您写了,

# changing "next" value of pointer does not affect L
P = L
P = P.next
L.iterateLL() # L is unchanged

但是,您没有 更改 下一个值。您 阅读 来自P.nextP.next在作业的右侧。为了更改P.nextP.next必须位于赋值运算符(=)的左侧

然后您编写:

# changing "next.next" value of pointer does affect L
P = L 
P.next = P.next.next
L.iterateLL() # now we've skipped node 2

这次,P.next在赋值运算符(=)的左侧。因此,您实际上进行了更改。

write_to = read_from
,

在大多数情况下,在Python中,当您对变量P执行赋值时,P的值会发生变化,但是对象是本来指没有。这是因为Python变量只是对象的引用/指针。这是一个示例:

var1 = "test1"
var2 = "test2"
var3 = var1 # var3 = "test1"
var1 = var2 # var1 = "test2"

print(var1) # "test2"
print(var2) # "test2"
print(var3) # "test1"

那么这里发生了什么?好吧,我们只是在更改这些变量所指向的内容,而没有更改基础对象。

现在,您要执行以下操作:

# changing value of pointer does not affect L
P = L
P = P.next
L.iterateLL() # L is unchanged

当您执行P = LP = P.next时,您只是在更改变量P指向的内容。您没有更改P指向的基础对象。让我们对其进行可视化。

原始配置: Original Configuration

P = L

P = L

P = L.next

P = L.next

但是,当您这样做

P = L
P.next = P.next.next
L.iterateLL() # we've now skipped node two

您正在更改P所指向的对象的属性。您正在将属性P.next设置为指向P.next.next。您实际上并没有更改P.next最初指向的基础对象。这样,P.next最初指向的对象将超出范围,并由垃圾收集器清除。

P.next = P.next.next

P.next = P.next.next

从您的代码来看,我假设您在这种情况下的预期行为是从LinkedList中删除L,最后得到一个类似“ 2 3 4”的列表。为此,只需进行L = L.next就可以了。这将导致第一个节点超出范围,垃圾收集器应对其进行清理。

作为一个简短的警告,我提到在大多数情况下,赋值不会更改变量所指向的对象。但是,属性有些不同。它们覆盖了__set__魔术方法,该方法使您可以使用赋值运算符编辑基础对象。这里不是这种情况。

本文链接:https://www.f2er.com/3140704.html

大家都在问