edubun
Español

Listas enlazadas

Agregar un valor al principio de una lista enlazada cambia dos punteros, tenga la lista 4 valores o 4 millones.

Valores que apuntan al siguiente

Un arreglo guarda sus valores uno al lado del otro, y por eso cambiar el principio es caro. Una lista enlazada abandona esa regla. Cada valor vive en su propio registro pequeño llamado nodo, y los nodos pueden estar en cualquier lugar de la memoria. Las notas del 6.006 del MIT describen un nodo con dos campos: el elemento (item) y next, un puntero al nodo siguiente. La lista en sí solo recuerda el primer nodo, llamado cabeza (head). El next del último nodo es null, lo que marca el final.

Para leer la lista empiezas en head y sigues los punteros next uno por uno, como quien sigue una cadena de notas en la que cada una dice dónde está escondida la siguiente. Eso tiene un costo. No hay fórmula para la dirección del cuarto nodo, así que obtener el valor de la posición i significa visitar i + 1 nodos. El MIT da get at(i) para una lista enlazada como O(n), mientras que el arreglo lo resolvía en un paso.

// un nodo por valor: { value, next }
let head = null;
for (const v of [4, 30, 7, 12]) head = { value: v, next: head };
// recorrer la lista
for (let n = head; n !== null; n = n.next) console.log(n.value); // 12, 7, 30, 4

Cambiar la lista volviendo a enlazar

La ventaja aparece cuando cambias la lista. Para poner un valor nuevo al principio, crea un nodo cuyo next sea la cabeza actual y luego haz que head apunte al nodo nuevo. Dos cambios de puntero, y nada más se mueve. Eliminar el primer nodo es un solo cambio: hacer que head apunte a head.next. Compáralo con el arreglo, donde las mismas operaciones movían todos los valores.

En el medio, el trabajo está en encontrar el lugar. Para insertar en la posición i, recorres hasta el nodo justo anterior (i visitas) y luego haces los mismos dos cambios de puntero: new.next = prev.next y después prev.next = new. El orden importa. Si cambias primero prev.next, el resto de la lista se pierde, porque ya nada apunta a él. En el laboratorio, un paso es un nodo visitado o un puntero cambiado, así que insertar en la posición 2 de una lista de 4 nodos cuesta 2 visitas más 2 cambios, 4 pasos.

Cargando

Arrastra para girar. Desplaza o pellizca para acercar.

Una lista simplemente enlazada de cuatro nodos. Elige una posición con el control deslizante e inserta o elimina; el contador separa los nodos visitados de los punteros cambiados. Buscar recorre desde head hasta que encuentra el valor o llega a null.
OperaciónArreglo (n valores)Lista enlazada (n nodos)
Obtener el valor de la posición i1i + 1 visitas
Insertar al principion movimientos + 1 escritura2 cambios de puntero
Eliminar el primero1 lectura + (n − 1) movimientos1 cambio de puntero
Insertar en la posición i(n − i) movimientos + 1 escriturai visitas + 2 cambios
Buscar un valorhasta n lecturashasta n visitas

Cuándo usarla

Una lista enlazada encaja bien cuando la mayoría de los cambios ocurren en un lugar al que ya tienes un puntero, como el principio, y casi nunca necesitas la posición i. Las colas y las pilas se pueden construir con listas enlazadas, y también las cadenas dentro de una tabla hash de la unidad siguiente. Hay variantes. Una lista doblemente enlazada le da a cada nodo también un puntero prev, así que puedes recorrerla hacia atrás y eliminar un nodo en un paso una vez que lo tienes. Guardar un puntero tail además de head hace barato agregar al final.

En el JavaScript de todos los días casi nunca se escribe una lista enlazada, porque los arreglos están muy optimizados y las cachés de los procesadores modernos favorecen los valores guardados uno junto a otro. Aun así, la idea importa: los árboles, los grafos y muchas estructuras de las bibliotecas se construyen con nodos y punteros exactamente de esta manera.

ContextoLas listas enlazadas aparecieron a mediados de la década de 1950 con el Information Processing Language (IPL), escrito por Allen Newell, Cliff Shaw y Herbert Simon en la RAND Corporation y el Carnegie Institute of Technology hacia 1956. Sus programas buscaban demostraciones de teoremas de lógica, y no se podía saber de antemano cuántas cosas ni de qué tamaño tendrían que recordar. Las listas de celdas enlazadas permitían repartir y recuperar la memoria celda por celda. El procesamiento de listas de IPL influyó en Lisp, que John McCarthy diseñó unos años después.
  1. ¿Qué dos campos tiene un nodo de una lista simplemente enlazada?
    • item y next
    • index y value
    • left y right
    • head y tail
  2. Lista 12 → 7 → 30 → 4. ¿Cuántos pasos lleva insertar un valor nuevo al principio (cambios de puntero)?
  3. La misma lista: insertar en la posición 2 cuesta cuántos pasos (visitas más cambios de puntero)?
  4. La misma lista: ¿cuántos nodos visita una búsqueda de 30?
  5. La misma lista: ¿cuántos nodos visita una búsqueda de 99 antes de llegar a null?
  6. La misma lista: eliminar el nodo de la posición 3 (el 4) cuesta cuántos pasos?
  7. Un arreglo contiene 1000 valores y tiene espacio de sobra. ¿Cuántos pasos lleva insertar al principio?
  8. ¿Qué tarea le conviene más a una lista enlazada que a un arreglo?
    • Leer muchas veces el valor de la posición 500
    • Agregar y quitar muchas veces al principio
    • Búsqueda binaria
    • Ordenar por índice
  9. Al insertar después del nodo p, ¿qué orden de pasos conserva el resto de la lista?
    • p.next = new y luego new.next = p.next
    • new.next = p.next y luego p.next = new
    • Funciona en cualquier orden
    • Eliminar p primero
  10. ¿Qué lenguaje, escrito hacia 1956 en RAND, introdujo el procesamiento de listas con celdas enlazadas?
    • Fortran
    • IPL
    • C
    • JavaScript
Ideas clave
  • Una lista enlazada guarda cada valor en un nodo con un puntero next; la lista guarda head.
  • Insertar o eliminar al principio cambia 1 o 2 punteros; nada se mueve.
  • Llegar a la posición i lleva i + 1 visitas, así que get at(i) es O(n).
  • Fija new.next antes de volver a enlazar el nodo anterior.
Fuentes de este curso (11)
  • MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
  • lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append)
  • 4 Hashing (chaining, pigeonhole collisions, chain length n/m)
  • 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
  • MDN Web Docs, Array.prototype.shift (shifts all values left by 1)
  • Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
  • ECMAScript 2025 Language Specification (tc39.es/ecma262)
  • 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements")
  • Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
  • D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
  • "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).

Fecha de consulta: 2026-10-18