head.next在单链接列表中的更改方式



我在简单的单链表中有一个很大的困惑,比如:在java中。

节点类别:

public class node {
    public int data;
    public node next;
    public node(int data , node next) {
       this.data = data;
       this.next = next; 
    }
}

链表类:

public linked list{
    public node first;
    public node last;
    public void add(int data){
        node x = new node(data,null);
        if( first == null ) { first= x; }
        else { last.next = x; }
        last = x;
    }
}

这里最大的困惑是,如果链表是空的,并且我正在尝试添加新节点,例如:add(1);

第一个节点的数据将为1,第一个节点下一个节点将为null并且最后一个节点的数据将为1,并且最后一节点的下一个节点将为空

现在,如果我添加了一个新节点,例如:add(2);

最后一个节点的数据将为2,最后一个结点的下一个将为空第一个节点的数据仍然是1,但第一个节点下一个节点将是尾部,这是怎么发生的?

单独链接列表中的head.next是如何更改的?

在single-linkedlist中head.next是如何更改的?

简短回答:因为最初firstlast都指向同一个节点,所以last.next = x间接导致first.next = x


长答案

它的核心是对象引用(指针)。

要理解它为什么会改变,首先你必须了解指针在Java中是如何工作的,Java是一种非常高级的语言,在这里你可以避免所有讨厌但乏味的内存操作。

tldr;我想推荐你看这个史诗般的视频,谈论指针,宾基指针视频


指针在Java中的工作原理

1.内存分配:

下面的语句分配新的内存来保存节点值(data&next)。x现在保持地址值,即:0x1ACD到实际节点值。换句话说,x是一个节点指针。

  node x = new node(data,null); //0x1ACD

2.指针取消引用:

为了访问实际的节点值,我们需要取消对地址值的引用。当您访问Object中的属性(即:node.Next)时,指针将被取消引用。以下语句取消引用last和对象分配将x中的地址值复制到nextlast中的属性)。

  last.next = x;

3.对象分配:

由于内部Java设计(内存效率),对象分配只复制地址值,而不是克隆整个节点值(在现实世界中,它可能很大)。

firstlast现在保持与x相同的地址值,即实际节点值的地址。

public void add(int data){
    ...
    first = x; 
    last = x;
    ...
}

你可能会问,这有什么了不起的地方?举以下例子:

public void add(int data){
    ...
    first = x; 
    last = x;
    last.next = new node(123,null);
    ...
}

请注意,现在,last.next == first.next。通过last更改节点值似乎也会修改first,因为它们都指向相同的节点值。

这是如何在单链列表中更改head.next的完整答案

参考文献:

  1. https://softwareengineering.stackexchange.com/questions/207196/do-pointers-really-exist-in-java
  2. https://softwareengineering.stackexchange.com/questions/141834/how-is-a-java-reference-different-from-a-c-pointer

插图:

步骤1:当我们add(1)到一个空列表时:

public void add(int data) {
    ...
    first= x; 
    ...
    last = x;
    ...
} 
// after:
   [1] <- first, last           // first and last now pointing to the same `node:x`.  
    |
   [/] <- first.next, last.next // first.next, last.next pointing to null.

步骤2:现在,当我们add(2)到上一个列表(非空)时:

// before:
   [1] <- first, last          
    |
   [/] <- first.next, last.next // first.next, last.next pointing to null.
public void add(int data) {
    ...
    // technically, since first and last pointing to the same node[1],
    // x actually being assigned to both first.next and last.next.
    last.next= x; 
    ...
    last = x;     // update last from previous-x to current-x.
    ...
} 
// after:
   [1] <- first
    |
   [2] <- last      // first.next, last is pointing to the new `node:x`.
    |
   [/] <- last.next // last.next to null.

步骤3等:现在,让我们add(3)或列表中的后续值(非空):

// before:
   [1] <- first
    |
   [2] <- last      
    |
   [/] <- last.next // last.next to null.
public void add(int data) {
    ...
    last.next= x; // access previous-x and assign x to previous-x's next.
    ...
    last = x;     // update last from previous-x to current-x.
    ...
} 
// after:
   [1] <- first
    |
   [2]         
    |
   [3] <- last      // last is pointing to the new `node:x`. 
    |
   [/] <- last.next // last.next to null.

注:

  • first总是指向列表中的第一个节点。

  • last总是指向列表中的最后一个节点。

  • last.next总是指向null。通过Add(),新节点总是通过分配给last.next而附加到列表的末尾。

最新更新