首页 > 解决方案 > 为什么 this.tail 在我的 Linkedlist 类中更改 this.head 的属性?

问题描述

考虑一个模仿 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 的下一个属性?

此外,当将另一个数字附加到 listmyLinkedList.append(16)时,它会不断更新 head 的 next 属性,如下所示:

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 等等?

标签: javascriptclassooplinked-listthis

解决方案


当构造函数运行this.tailthis.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调用时,第二个next对象的属性会更新,所以我们得到:

     this.head                         newNode
      ↓                                 ↓
    ┌───────────┐    ┌───────────┐    ┌───────────┐
    │ value: 10 │    │ value: 5  │    │ value: 16 │
    │ next: ———————→ │ next: ———————→ │ next:null │
    └───────────┘    └───────────┘    └───────────┘
                                        ↑
                                       this.tail

是的,这个变化也是可追溯的this.head,因为……它是一个链表……所以它应该是可追溯的。由于每个next属性都指向下一个节点,因此您可以找到从head任何节点到任何节点的方式。


推荐阅读