Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在链表操作中使用sentinel节点_Java_Data Structures_Linked List_Reference - Fatal编程技术网

Java 在链表操作中使用sentinel节点

Java 在链表操作中使用sentinel节点,java,data-structures,linked-list,reference,Java,Data Structures,Linked List,Reference,我在Leetcode上解决了一个问题,通过提供的解决方案,我遇到了“哨兵/虚拟节点”的概念。在某些情况下,使用这样的节点可以简化链表中的操作,例如空列表或包含一个元素的列表等 问题描述是- 从具有值的整数链表中删除所有元素 瓦尔 例如: 输入:1->2->6->3->4->5->6,val=6输出:1->2->3->4->5 给出的解决方案是- class Solution { public ListNode removeElements(ListNode head, int val) {

我在Leetcode上解决了一个问题,通过提供的解决方案,我遇到了“哨兵/虚拟节点”的概念。在某些情况下,使用这样的节点可以简化链表中的操作,例如空列表或包含一个元素的列表等

问题描述是-

从具有值的整数链表中删除所有元素 瓦尔

例如:

输入: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=头部
我们将
sentinel
作为列表中的第一个节点,它的
next
节点是“head”,如下所示-
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=新的ListNode(0);
sentinel.next=头部;
ListNode prev=哨兵,curr=头部;
我们得到这样的东西-
[sentinel]->[head]
,其中
prev
指向
sentinel
curr
指向
head

但问题是
prev
curr
在列表期间都会更改引用,而
sentinel
head
则不会。因此,
sentinel.next
仍然指向旧的
头部

编辑1 为了让我的问题更清楚,这里有一个例子。我想知道的是,
sentinel.next
如何引用值为
2
的节点?开始时,
sentinel.next
被设置为
head
,这在任何地方都没有改变。因此,
sentinel.next
应该引用列表的原始
——值为
1的节点

编辑2 我想我现在明白了。更改发生在此行
prev.next=curr.next

因为
prev
sentinel
都引用相同的列表元素(在这个阶段),
sentinel.next
设置正确。

  • 我想这可能是不正确的:
当我们运行return sentinel.next->时,我们首先得到一个对此的引用 列表中的节点

  • prev
    对于前两个值不会移动,我猜。仅将其链接移动到下一个节点

  • 另一件事是sentinel是
    最终版
    ,不会改变:

  • 也许我们应该注意到,我们没有删除任何值(值在内存中),我们只是更改链接列表的链接

  • 最后,我们只对链表的标题感兴趣,它将是
    sentinel。接下来
    ,我们不想看到
    prev
    在哪里

迭代地


1和1之间的链接仍然存在,忘了画它。

是的,
prev
对于两个
1
s不移动,但是对于
2
3
,所以当循环结束时,
prev
处于
3
。我添加了一个print语句,返回的值显示为“2”。屏幕截图-但这是我的问题-
sentinel.next
如何引用
2
,当它应该引用原始
头部时。
class Solution {
    public ListNode removeElements(
        final ListNode head,
        final int val
    ) {
        final ListNode sentinel = new ListNode(0);
        sentinel.next = head;

        ListNode prev = sentinel;
        ListNode curr = head;

        while (curr != null) {
            if (curr.val == val) {
                prev.next = curr.next;
            }

            else {
                prev = curr;
            }

            curr = curr.next;
        }

        return sentinel.next;
    }
}
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if (head == null)
            return null;

        head.next = removeElements(head.next, val);
        return head.val == val ? head.next : head;
    }
}