Рассмотрим класс 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 и так далее?
Первое добавление - это ожидал для обновления заголовка (потому что в начале заголовок является хвост). Второе дополнение не обновляет head, это просто console.info, который представляет его таким образом. То есть ваш код в порядке.
(Единственное, что странно в вашем коде, это то, что связанный список всегда состоит как минимум из одного элемента и не может быть пустым)
Это не мой код (да, он должен работать таким образом, но я не понимал, как он работает, поэтому я спросил: D (немного подумав, tbh)) Так что на самом деле это просто ссылка на объект. Контрольный объект головы присваивается хвосту. когда я использую tail.next, он также обновляет объект, на который он ссылается, который является head.next. Верно?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Когда конструктор запущен, 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 свойство next объекта второй будет обновлено, и мы получим:
this.head newNode
↓ ↓
┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 10 │ │ value: 5 │ │ value: 16 │
│ next: ———————→ │ next: ———————→ │ next:null │
└───────────┘ └───────────┘ └───────────┘
↑
this.tail
И да, это изменение также можно отследить от this.head, потому что ... это связанный список ... так что можно отследить должен. Поскольку каждое свойство next относится к следующему узлу, вы можете найти свой путь от head к любому из узлов.
Спасибо за вашу простую для понимания иллюстрацию! Я очень ценю это!
«Может быть, возможная причина связана с конструктором, в котором я определяю
this.tail = this.head?» - да, конечно, причина в этом: оба свойства теперь содержат одну и ту же ссылку на объект, а затем вы меняете свойство.nextэтого объекта, на который ссылаются из обоих мест.