head.next如何在单链表中更改

时间:2016-05-12 00:31:37

标签: java algorithm oop data-structures linked-list

我在简单的单链表中有一个很大的困惑,例如: 在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,第一个节点的下一个节点为空 并且最后一个节点的数据将为1,最后一个节点的下一个节点将为空

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

最后一个节点的数据为2,最后一个节点的数据为空 并且第一个节点的数据仍然是1但是第一个节点的下一个将是尾部,这是怎么回事?

如何在单链表中更改head.next?

1 个答案:

答案 0 :(得分:1)

  

如何在单链表中更改head.next?

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

答案很长

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

要理解它为什么会发生变化,首先你必须要理解指针在Java中是如何工作的,这是一种非常高级的语言,你可以将它隐藏在所有令人厌恶但又乏味的内存操作中。

tldr;我会建议你观看这个史诗般的视频,它谈论指针,Binky Pointer Video

Pointer如何在Java中工作

<强> 1。内存分配:

下面的语句分配新的存储器来保存节点值(数据和下一个)。 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
  3. 插图:

    第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附加到列表末尾。