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

2024-09-17 19:43:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个单链表,L,并创建一个指向这个列表p的指针。似乎有时修改p会改变实际的列表,而其他时候修改p不会改变实际的列表L,只会改变p所指向的内容。你知道吗

假设我创建了一个指向L的指针,p=L(在python中)。做类似于P=P.next的事情会使L保持不变,但是P.next=P。下一个。下一个类似地,通过修改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会影响L?如果所有这些操作都以相同的方式执行,那么改变指针是否总是改变链表(因此P=P.next应该通过去掉第一个节点来修改L),或者从不改变链表(因此P.next=P。下一个。下一个我应该保持原样吗?你知道吗

我有一种感觉,这与L.next是指针这一事实有关,就像p.next一样。所以修改P.next的结果就是修改L.next指向的(?)。但我觉得规则对我来说并不清楚。你知道吗


Tags: selfnonenode列表dataisdefval
2条回答

你写道

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

但是,您没有更改下一个值。您可以从P.next读取。P.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__魔术方法,该方法允许您使用赋值操作符编辑基础对象。这里不是这样。你知道吗

相关问题 更多 >