考虑一个模仿 Linkedlist 数据结构的 LinkedList 类,如下所示:
class LinkedList {
constructor(value) {
this.head = {
value: value,
next: null
};
this.tail = this.head;
this.length = 1;
}
append(value) {
const newNode = {
value: value,
next: null
}
this.tail.next = newNode; // why does this change head.next ?
this.tail = newNode;
this.length++;
return this;
}
}
let myLinkedList = new LinkedList(10);
myLinkedList.append(5);
日志输出
LinkedList {
head: { value: 10, next: { value: 5, next: null } },
tail: { value: 5, next: null },
length: 2
}
我看到
this.tail.next
也会更改 tail 的下一个属性(然后 this.tail = newNode
会将 tail 重新分配给 newNode)。我在这里不明白的是为什么 this.tail.next
也会改变 this.head 的下一个属性?
此外,当向列表添加另一个数字时
myLinkedList.append(16)
,它会不断更新 head 的下一个属性,如下所示:
LinkedList {
head: { value: 10, next: { value: 5, next: [Object] } },
tail: { value: 16, next: null },
length: 3
}
也许一个可能的原因与我定义
this.tail = this.head
的构造函数有关?但我不太确定,因为这个只分配从头到尾的值。
总而言之,我的问题是为什么
this.tail.next = newNode
会改变头部的下一个属性?另外,当附加另一个值时,为什么它会改变 head.next.next 等等?
当构造函数运行时,
this.tail
和 this.head
引用同一个对象,因此您对 this.tail.next
所做的任何赋值都在 this.head
中可见,因为这实际上是对正在变异的同一对象的引用。
这可能有助于形象化这一点。一旦构造函数运行,我们就会遇到这种情况:
this.head
↓
┌───────────┐
│ value: 10 │
│ next: null│
└───────────┘
↑
this.tail
然后
append(5)
会先创建一个新节点:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next:null │ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
然后执行
this.tail.next = newNode;
,这是对第一个对象中的next
属性的修改:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next: ———————→ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
所以确实,这也会改变
this.head.next
...因为它只是相同的属性。
然后执行
this.tail = newNode;
:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │
│ next: ———————→ │ next:null │
└───────────┘ └───────────┘
↑
this.tail
下次调用
append
时,second对象的
next
属性将被更新,所以我们得到:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │ │ value: 16 │
│ next: ———————→ │ next: ———————→ │ next:null │
└───────────┘ └───────────┘ └───────────┘
↑
this.tail
是的,这个变化也是可以从
this.head
追溯到的,因为……它是一个链表……所以它应该是可追溯的。由于每个 next
属性都引用下一个节点,因此您可以找到从 head
到任何节点的路径。
哇上面的答案比水还清楚