【发布时间】:2020-08-31 18:32:12
【问题描述】:
我在 Leetcode 上的 Remove Linked List elements 上解决了一个问题,当时我通过提供的解决方案遇到了“哨兵/虚拟节点”的概念。在某些情况下,使用这样的节点应该会使链接列表中的操作更容易,例如空列表或具有一个元素的列表等。
问题描述是-
从具有值的整数链表中删除所有元素 值。
例子:
输入:1->2->6->3->4->5->6,val = 6 输出:1->2->3->4->5
给定的解决方案是 -
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel, curr = head;
while (curr != null) {
if (curr.val == val) prev.next = curr.next;
else prev = curr;
curr = curr.next;
}
return sentinel.next;
}
}
让我们考虑这个链表 -
1 -> 1 -> 2 -> 3 -> NULL,要移除的节点值为1。
因此,结果列表应该是2 -> 3 -> NULL,其中该列表的head 指向2。
在这一行 - sentinel.next = head; 我们将 sentinel 作为列表中的第一个节点,它的 next 节点是“头”,就像这样 -
0 -> 1 -> 1 -> 2 -> 3 -> NULL,
-
请注意,
head仍指向1(列表中值为 1 的第一个节点)。 -
在while循环开始之前,我们将
prev设置为sentinel,将curr设置为head。 -
在循环期间,
prev和curr沿着列表移动,都指向列表中的其他节点。请注意,head仍然指向第一个 1。 -
循环之后,
prev指向列表中的最后一个节点(值为 3),而curr变为null。 -
但是,
head仍然指代列表中的第一个节点(值为 1),sentinel.next指代这个节点。因此,当我们运行return sentinel.next-> 时,我们会获得对列表中第一个节点的引用(值为 1),其next属性不指向任何其他节点。所以这本身就是一个节点。
那么这如何正确工作呢?应该返回的ListNode 应该引用值为2 的节点,而不是1。
这是基于我对 Java 中引用如何工作的了解。因为,当我们从这个开始时 -
ListNode sentinel = new ListNode(0);
sentinel.next = head;
ListNode prev = sentinel, curr = head;
我们得到这样的东西 - [sentinel] -> [head] prev 指向 sentinel 和 curr 指向 head。
但问题是prev 和curr 在列表期间都会更改引用,而sentinel 和head 不会。所以,sentinel.next 仍然指向旧的head。
编辑 1
为了让我的问题更清楚,这里是screenshot of the result。我想知道的是-sentinel.next 如何引用值为2 的节点?一开始,sentinel.next 被设置为head,这在任何地方都没有改变。所以,sentinel.next 应该引用列表的原始head - 值为1 的节点。
编辑 2
我想我现在明白了。变化发生在这一行prev.next = curr.next;
因为prev 和sentinel 都引用同一个列表元素(在这个阶段),所以sentinel.next 设置正确。
【问题讨论】:
标签: java data-structures linked-list reference