我在简单的单链表中有一个很大的困惑,例如: 在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?
答案 0 :(得分:1)
如何在单链表中更改head.next?
简短回答:由于最初first
和last
都指向同一个节点,last.next = x
间接导致first.next = x
。
答案很长:
它的核心是对象引用(指针)。
要理解它为什么会发生变化,首先你必须要理解指针在Java中是如何工作的,这是一种非常高级的语言,你可以将它隐藏在所有令人厌恶但又乏味的内存操作中。
<强> 1。内存分配:
下面的语句分配新的存储器来保存节点值(数据和下一个)。 x
现在保持地址值,即:0x1ACD
到实际节点值。换句话说,x
是一个节点指针。
node x = new node(data,null); //0x1ACD
<强> 2。指针解除引用:
为了访问实际的节点值,我们需要取消引用地址值。当您访问Object中的属性时,会发生指针解除引用,即:node.Next
。以下语句解除引用last
和对象分配将x
中的地址值复制到next
(last
中的属性)。
last.next = x;
第3。对象分配:
由于内部Java设计(内存效率),而不是克隆整个节点值(在现实世界中,它可能很大),对象分配只复制地址值。
first
和last
现在拥有与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步:当我们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
附加到列表末尾。