Listas enlazadas: Teoría

En este vídeo te cuento qué es una lista enlazada, cómo se representa de forma gráfica y cuáles son las principales operaciones que podemos hacer con una lista, como agregar o quitar elementos.

Las listas enlazadas son una estructura de datos fundamental que nos permite almacenar elementos en una secuencia dinámica mediante nodos conectados por punteros. A diferencia de los arrays, que requieren que sus elementos estén almacenados en posiciones contiguas de memoria, las listas enlazadas pueden tener sus nodos dispersos en memoria, siempre que cada nodo conozca la dirección del siguiente. Esto nos ofrece una gran flexibilidad para manejar colecciones de datos cuyo tamaño puede variar durante la ejecución del programa.

Cada nodo en una lista enlazada contiene un elemento, que puede ser de cualquier tipo, desde un entero hasta una estructura compleja como un libro con título, autor e ISBN, y un puntero que apunta al siguiente nodo en la secuencia. La lista en sí se maneja a partir de un nodo especial llamado cabeza, que es el único punto de acceso necesario para recorrer toda la lista. Desde la cabeza, podemos seguir los punteros para acceder a cada nodo sucesivo hasta llegar al final, que se indica con un puntero nulo, señalando que no hay más elementos.

Una característica interesante es que la cola de una lista, es decir, todos los nodos excepto la cabeza, también puede considerarse una lista enlazada por sí misma. Esto crea una estructura recursiva donde cada cola es otra lista, hasta llegar a la lista vacía que marca el final.

Entre las ventajas de las listas enlazadas destaca la capacidad de crecer o reducirse dinámicamente sin necesidad de reservar memoria contigua, lo que las hace ideales para situaciones donde el tamaño de la colección no es conocido de antemano o cambia frecuentemente. Sin embargo, tienen algunas desventajas, como la falta de acceso aleatorio a los elementos, ya que para llegar a un nodo en particular debemos recorrer la lista desde la cabeza. Además, cada nodo consume memoria adicional para almacenar el puntero al siguiente nodo.

Para manejar listas enlazadas, podemos definir una estructura nodo que contenga el elemento y el puntero al siguiente nodo, y una estructura lista que mantenga un puntero a la cabeza. Esto nos permite añadir metadatos adicionales a la lista, como su longitud, si lo deseamos.

Crear un nodo es sencillo: basta con asignar el elemento deseado y establecer su puntero siguiente a nulo, ya que inicialmente no sabemos qué nodo vendrá después. Para recorrer una lista, podemos usar un puntero que comience en la cabeza y avanzar por cada nodo hasta que el puntero siguiente sea nulo. Esto se puede implementar con un bucle que procesa cada elemento y actualiza el puntero para avanzar al siguiente nodo.

Nodo puntero = lista.cabeza;
while (puntero != null) {
    // Procesar el elemento del nodo actual
    System.out.println(puntero.elemento);
    puntero = puntero.siguiente;
}

Insertar elementos en una lista enlazada puede hacerse en diferentes posiciones. Si la lista está vacía, simplemente creamos un nuevo nodo y lo asignamos como cabeza. Para insertar al principio, creamos un nuevo nodo, hacemos que su puntero siguiente apunte a la cabeza actual y luego actualizamos la cabeza para que sea este nuevo nodo.

Nodo nuevoNodo = new Nodo(elemento);
nuevoNodo.siguiente = lista.cabeza;
lista.cabeza = nuevoNodo;

Agregar un elemento al final requiere recorrer la lista hasta encontrar el último nodo, cuyo puntero siguiente es nulo, y luego hacer que este apunte al nuevo nodo.

Para insertar un nodo en medio de la lista, por ejemplo después de un nodo con un valor específico, recorremos la lista hasta encontrar ese nodo, creamos el nuevo nodo, hacemos que su puntero siguiente apunte al nodo que sigue al nodo encontrado, y actualizamos el puntero siguiente del nodo encontrado para que apunte al nuevo nodo.

Eliminar nodos también implica manipular punteros con cuidado para no perder referencias y evitar fugas de memoria, especialmente en lenguajes que no gestionan automáticamente la memoria. Para eliminar el primer nodo, guardamos una referencia temporal al nodo cabeza, actualizamos la cabeza para que apunte al segundo nodo, y luego liberamos la memoria del nodo eliminado.

Eliminar el último nodo implica recorrer la lista hasta el penúltimo nodo, que es aquel cuyo siguiente apunta al último nodo. Guardamos una referencia al último nodo, actualizamos el puntero siguiente del penúltimo nodo a nulo, y liberamos la memoria del nodo eliminado.

Para eliminar un nodo intermedio, localizamos el nodo anterior al que queremos eliminar, actualizamos su puntero siguiente para que apunte al nodo que sigue al nodo a eliminar, y liberamos la memoria del nodo eliminado.

Estas operaciones básicas nos permiten manejar listas enlazadas de forma eficiente y flexible, adaptándonos a las necesidades de almacenamiento dinámico y manipulación de datos en nuestras aplicaciones. En futuras ocasiones podremos profundizar en cómo implementar estas operaciones en código real y explorar variantes como listas dobles o circulares.

Lista de reproducción
  1. 1
    Qué son las estructuras de datos
    3 minutos
  2. 2
    Listas enlazadas: Teoría
    12 minutos
  3. 3
    Listas enlazadas en C
    18 minutos
  4. 4
    Listas enlazadas en Java
    17 minutos
  5. 5
    Colas: teoría
    6 minutos
  6. 6
    Colas en C
    12 minutos
  7. 7
    Colas en Java
    10 minutos
  8. 8
    Pilas: teoría
    7 minutos
  9. 9
    Pilas en C
    11 minutos
  10. 10
    Pilas en Java
    10 minutos
  11. 11
    Introducción a los árboles
    11 minutos
  12. 12
    Árboles binarios
    9 minutos
  13. 13
    Árboles binarios de búsqueda (parte 1)
    10 minutos
  14. 14
    Árboles de búsqueda binaria (parte 2)
    8 minutos
  15. 15
    BSTs en C (parte 1)
    13 minutos
  16. 16
    BSTs en C (parte 2)
    8 minutos
  17. 17
    BSTs en C (y parte 3)
    18 minutos
  18. 18
    BSTs en Java (parte 1)
    9 minutos
  19. 19
    BSTs en Java (parte 2)
    11 minutos
  20. 20
    BSTs en Java (parte 3)
    10 minutos
  21. 21
    Árbol desde preorden e inorden
    8 minutos
  22. 22
    Árbol desde inorden y postorden
    8 minutos
  23. 23
    Árboles k-arios
    6 minutos
  24. 24
    Árboles B (parte 1)
    11 minutos
  25. 25
    Árboles B (parte 2)
    20 minutos
  26. 26
    Árboles B (parte 3)
    39 minutos