Tengo problemas para entender dónde va el primer nodo o el encabezado anterior en una lista vinculada.
class Node { constructor(val) { this.val = val; this.next = null; } } class SinglyLinkedList { constructor() { this.head = null; this.tail = null; this.length = 0; } push(val) { var newNode = new Node(val); if (!this.head) { this.head = newNode; this.tail = this.head; } else { this.tail.next = newNode; this.tail = newNode; } this.length++; return this; } shift() { if (!this.head) return undefined; var currentHead = this.head; this.head = currentHead.next; this.length--; if (this.length === 0) { this.tail = null; } return currentHead; } }Entiendo que agregamos una nueva variable para el encabezado anterior, luego movemos el encabezado al siguiente nodo, pero ¿a dónde va el encabezado anterior/nodo anterior? Veo que lo devolvemos, ¿es eso lo que lo borra/elimina de la lista? Sé que el código funciona, solo tengo curiosidad por saber adónde va ese nodo.
Estoy usando su código para crear una lista enlazada única que contendrá los valores de mi lista HTML.
Cuando presiona shift , ejecuta la función shift, donde se llama a su función shift.
Puede ver que estoy asignando el valor del nodo devuelto (el encabezado anterior) al contenido de texto de un elemento para que pueda ver el valor devuelto en la parte superior.
La función de actualización simplemente sincroniza la lista de su clase con la lista HTML.
function push() { const value = document.getElementById('input').value; value && list.push(value); update(); } function shift() { // Below i'm using the returned value of shift (the head of the list), // otherwise it would be lost, and there would be no reference to it, // so it would be collected by the Garbage collector document.getElementById('shifted').textContent = list.shift().val; update(); } function update() { const li = document.getElementById('list'); li.innerHTML = ''; let index = list.head; while (index) { const node = document.createElement('li'); node.textContent = index.val; li.appendChild(node); index = index.next; } } class Node { constructor(val) { this.val = val; this.next = null; } } class SinglyLinkedList { constructor() { this.head = null; this.tail = null; this.length = 0; } push(val) { var newNode = new Node(val); if (!this.head) { this.head = newNode; this.tail = this.head; } else { this.tail.next = newNode; this.tail = newNode; } this.length++; return this; } shift() { if (!this.head) return undefined; var currentHead = this.head; this.head = currentHead.next; this.length--; if (this.length === 0) { this.tail = null; } return currentHead; } } document.getElementById('push').addEventListener('click', push); document.getElementById('shift').addEventListener('click', shift); const list = new SinglyLinkedList(); // Adding some initial items to the list and displaying the list list.push("1"); list.push("2"); list.push("3"); update(); <p>The Shifted/Returned node value is <span id="shifted">Undefined</span></p> <button id="shift">Shift</button> <label for="add">Add a node to the list</label> <input id="input" name="add" type="text" /> <button id="push">Push</button> <ul id="list"> </ul>El futuro de ese nodo está en manos del código que llamó shift . Si la persona que llama ignora la referencia devuelta, ese nodo se volverá inalcanzable y el recolector de basura podría decidir liberar su memoria.
Digamos que tenemos una lista enlazada mylist con tres nodos (con valores 1, 2 y 3). Podemos visualizarlo de la siguiente manera (omito la length ya que no es relevante para la pregunta):
mylist ↓ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ head: ──────>│ val: 1 │ │ val: 2 │ │ val: 3 │ │ tail: ─────┐ │ next: ──────>│ next: ──────>│ next: null│ └───────────┘│ └───────────┘ └───────────┘┌>└───────────┘ └─────────────────────────────┘ Ahora, cuando llamamos a mylist.shift() , lo asignamos a currentHead y cambiamos el valor de head de la siguiente manera:
mylist currentHead ↓ ↓ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ head: ──────┐│ val: 1 │ │ val: 2 │ │ val: 3 │ │ tail: ─────┐││ next: ──────>│ next: ──────>│ next: null│ └───────────┘││└───────────┘┌>└───────────┘┌>└───────────┘ │└─────────────┘ │ └─────────────────────────────┘ Entonces, a menos que cualquier otro código contenga una referencia al nodo con valor 1, ahora solo hay una variable local currentHead que hace referencia a él. Esta variable llegará al final de su vida útil cuando la función regrese y, a medida que se devuelva su valor, ahora depende de la persona que llama al método capturarlo.
Así que digamos que la persona que llama hizo let node = mylist.shift() , entonces tendríamos esta situación (moví un poco las casillas):
node ↓ ┌───────────┐ │ val: 1 │ │ next: ─────┐ └───────────┘│ mylist │ ↓ │ ┌───────────┐└>┌───────────┐ ┌───────────┐ │ head: ──────>│ val: 2 │ │ val: 3 │ │ tail: ─────┐ │ next: ──────>│ next: null│ └───────────┘│ └───────────┘┌>└───────────┘ └──────────────┘ Sin embargo, si solo llamamos shift sin capturar el valor devuelto, como mylist.shift() , entonces no habría más referencias a ese nodo con valor 1:
┌───────────┐ │ val: 1 │ │ next: ─────┐ └───────────┘│ mylist │ ↓ │ ┌───────────┐└>┌───────────┐ ┌───────────┐ │ head: ──────>│ val: 2 │ │ val: 3 │ │ tail: ─────┐ │ next: ──────>│ next: null│ └───────────┘│ └───────────┘┌>└───────────┘ └──────────────┘En otras palabras, no habría forma en JavaScript de acceder de alguna manera a ese nodo. En ese caso, el nodo todavía está allí, tal vez por otro milisegundo, un minuto o una hora, pero es invisible para el programa y su destino ahora está completamente en manos del recolector de basura, que puede decidir en cualquier momento para liberar la memoria ocupada por ese nodo.