LeetCode中ListNode代码逻辑疑问:result为何未随result_tail指向改变?
咱们先把Python里变量和对象的关系掰明白:Python里的变量其实就是贴在对象上的便利贴,变量本身不存储数据,只是指向存储数据的对象。当你修改对象的属性(比如node.next = ...),是直接改对象本身,所有指向这个对象的变量都会看到变化;但如果是给变量重新赋值(比如a = b),只是把便利贴从原来的对象上撕下来,贴到另一个对象上,和原来的对象没关系了。
现在咱们一步步拆解你的代码和疑问:
代码步骤拆解
result = ListNode(0)
创建了一个ListNode对象(记为对象A:val=0, next=None),result这个便利贴贴在对象A上。此时result指向0 -> None。result_tail = result
给对象A再贴一张便利贴result_tail,现在result和result_tail都指向对象A,所以两者都是0 -> None。result_tail.next = ListNode(1)
这是修改对象A的属性:把对象A的next指向新创建的对象B(val=1, next=None)。现在对象A变成0 -> 1 -> None,因为result也指向对象A,所以result自然也是0 -> 1 -> None,这部分你的猜想是对的。result_tail = result_tail.next
这是变量重新赋值:把result_tail这个便利贴从对象A上撕下来,贴到result_tail.next指向的对象B上。此时result仍然贴在对象A上(还是0 -> 1 -> None),而result_tail现在指向对象B(1 -> None)。这一步没有修改任何对象的属性,只是移动了result_tail的指向,所以result不会发生变化——这就是你困惑的核心点!result_tail.next = ListNode(2)
现在修改的是对象B的next属性,让它指向新创建的对象C(val=2, next=None)。对象B变成1 -> 2 -> None,而对象A的next还是指向对象B,所以整个result链表就变成0 -> 1 -> 2 -> None了。result_tail = result_tail.next
再次移动result_tail的指向,把它贴到对象C上,此时result_tail指向2 -> None,result仍然指向对象A,链表结构保持0 -> 1 -> 2 -> None不变。
解答你的疑问
为什么
result_tail = result_tail.next时result不变?
因为这一步只是改变result_tail的指向,没有修改任何节点对象的属性。result始终指向链表的头节点(对象A),对象A的next还是指向对象B,所以result的结构还是0 -> 1 -> None。为什么当
result_tail指向1 -> 2 -> None时,result尾部扩展?
因为此时你修改的是对象B的next属性,而对象B是result链表的一部分(对象A的next指向它),所以整个链表的结构会跟着更新。该语句是否等价于
result_tail = result.next.next?
只有在当前result_tail指向对象B(也就是result.next)的时候,这两个语句的结果是一样的。但如果后续result_tail移动到了对象C,那么result_tail = result_tail.next会指向对象C的next(也就是None),而result.next.next还是指向对象C,所以两者并不等价——前者是跟随当前result_tail的指向移动,后者是固定从链表头的第二个节点的next移动。
内容的提问来源于stack exchange,提问作者user6703592

