【问题标题】:How to understand the data structure of Python Linked List in LeetcodeLeetcode中如何理解Python链表的数据结构
【发布时间】:2021-05-27 19:40:08
【问题描述】:

我真的被 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有不同的影响?

【问题讨论】:

  • 你并没有真正的链表数据结构。你有一个ListNode 类,它的实例可以使用 来构建一个链表,但是没有一个类可以封装链表的概念并提供像appendinsert、@987654334 这样的方法@、remove
  • 至于您的实际问题,请阅读nedbatchelder.com/text/names.html。赋值永远不会改变现有的值,只有 name 被赋值。
  • 是的,所以问题可能与ListNode 结构有关?我只是不明白为什么更改bb.next 会产生不同的影响a
  • 因为分配给b 对同一对象的其他引用没有影响。
  • 第一个绑定a.next = b的读取方式是“使a.next指向当前b指向的同一事物”,然后第二个绑定b = None应该读为“现在让 b 不指向任何东西”。这样看,更清楚一点,第二次绑定对a.next没有影响。

标签: python data-structures linked-list


【解决方案1】:

绘制图表会有所帮助。这是您的链接列表:

[   ]
  |
  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 后仍继续存在的方式。

【讨论】:

    【解决方案2】:

    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)

    【讨论】:

      【解决方案3】:

      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.next 和 @987654337 @。

      请注意,b.next = ... 之类的赋值与 b = ... 非常不同。后者是“真正的”赋值,而前者是函数调用的特殊语法,如setattr(b, 'next', ...)。它修改了一些对象(特别是其属性的值),而不是仅仅使名称指向其他对象。

      【讨论】:

        猜你喜欢
        • 2017-01-10
        • 2016-03-30
        • 1970-01-01
        • 1970-01-01
        • 2021-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多