如何理解Leetcode中Python链表的数据结构



Leetcode中使用的Python链表数据结构让我非常困惑。我不确定这个问题是由Leetcode创建的特定ListNode结构引起的,还是我对Python有一些误解。例如,下面的一段代码很简单并且可以自我解释:

# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
def main():
# Instantiate a linked list 1 -> 2 -> 3
a = ListNode(1)
b = ListNode(2)
c = ListNode(3)
a.next = b
b.next = c
print(a) # a is 1 -> 2 -> 3
b.next = None
print(a) # a is 1 -> 2
b = None
print(a) # a is still 1 -> 2, why changing b doesn't change a, but changing b.next changes a???

假设我有一个链表a->b->c.当我设置b.next = Nonea.next.next = None。然而,让我困惑的是,当我设置b = None时,a.next并没有变成None。操作bb.next有什么区别,为什么它们对a有不同的影响?

绘制图表有帮助。这是你的链接列表:

[   ]
|
v
[   ]
|
V
[   ]
|
V
None

从框中引出的每个箭头表示该节点的next属性。

以下是三个变量abc:

[   ] <-- a
|
v
[   ] <-- b
|
V
[   ] <-- c
|
V
None

这些变量中的每一个还指向一个特定的节点。

如果说b.next = None,则b引用的节点的next属性将被修改,如下所示:

[   ] <-- a
|
v
None <-- [   ] <-- b

[   ] <-- c
|
V
None

这将修改列表的结构。不过,如果您只是将b本身设置为不同的值,则会发生以下情况:

[   ] <-- a
|
v
None <-- [   ]     b --> None

[   ] <-- c
|
V
None

您更改了b,但b用来指向的节点保持原样。请注意,这类似于c节点在设置b.next = None之后仍然存在的情况。

Python没有双指针,例如**x

b.next = c
print(a) # a is 1 -> 2 -> 3
b.next = None

例如,在上面,它并不意味着c is None

a.nextb时,如果更改a.next.next,则实际上是在更改b.next

但如果将a.next更改为None,则不会将b设置为None

编辑:

同样,当您设置b = Nonea.next仍指向ListNode(2)

a是对ListNode(1)的引用。对ListNode(2)有两个引用:一个存储在ListNode(1)中,被引用为a.next,另一个在b中。

把这些参考文献想象成箭头。

当您指定b = None时,只需将箭头b删除到ListNode(2),并将其替换为从bNone的箭头。这对从ListNode(1)ListNode(2)的箭头没有影响。

如果您改为对ListNode(3)进行更改,那么该更改将从所有三个引用中可见:a.next.nextb.nextc

注意,像b.next = ...这样的分配与b = ...非常不同。后者是一个";真";赋值,而前者是像setattr(b, 'next', ...)这样的函数调用的特殊语法。它在适当的位置修改一些对象(特别是它的一个属性的值(,而不仅仅是使名称指向其他对象。

最新更新