Listas enlazadas en Java

En este ejemplo completo te enseñaré cómo construir una lista enlazada en Java definiendo las estructuras y las operaciones.

Vamos a implementar una lista enlazada en Java para manejar una colección de libros, como si tuviéramos una biblioteca. La idea es construir una estructura que nos permita insertar, eliminar y recorrer libros de manera eficiente.

Primero, definimos una clase llamada Lista que contendrá una clase interna llamada Nodo. Cada nodo tendrá una referencia a un libro y otra al siguiente nodo en la lista. Esto nos permitirá enlazar los libros uno tras otro. La cabeza de la lista será un nodo especial que apunta al primer libro, o será null si la lista está vacía.

Para insertar un libro al principio, creamos un nuevo nodo con el libro que queremos añadir. Luego, hacemos que el siguiente de este nuevo nodo sea la cabeza actual de la lista, y finalmente actualizamos la cabeza para que apunte a este nuevo nodo. Así, el nuevo libro queda al inicio.

Insertar al final requiere recorrer la lista hasta llegar al último nodo, que es aquel cuyo siguiente es null. Para recorrer, usamos un puntero que comienza en la cabeza y avanzamos mientras el siguiente nodo no sea null. Cuando llegamos al final, asignamos el siguiente del último nodo al nuevo nodo que contiene el libro que queremos añadir.

Si queremos insertar un libro en medio de la lista, por ejemplo después del libro número n, creamos un método que reciba el índice n y el libro a insertar. Primero comprobamos si la lista está vacía; si es así, simplemente añadimos el nodo como cabeza. Si no, recorremos la lista con un contador que empieza en cero y avanzamos hasta llegar al nodo número n. Una vez allí, conectamos el nuevo nodo entre el nodo n y el nodo n+1, asegurándonos de que el nuevo nodo apunte al siguiente del nodo n, y que el nodo n apunte al nuevo nodo.

Para obtener un libro en una posición determinada, recorremos la lista con un contador hasta llegar al índice deseado. Si la lista está vacía o el índice es mayor que la longitud de la lista, devolvemos null. Si encontramos el nodo, devolvemos el libro que contiene.

Para saber cuántos libros hay en la lista, mantenemos una variable longitud que incrementamos cada vez que insertamos un libro y decrementamos cuando eliminamos uno. Así evitamos recorrer la lista para contar sus elementos, lo que mejora la eficiencia.

Eliminar el primer libro es sencillo: actualizamos la cabeza para que apunte al segundo nodo, y desconectamos el nodo eliminado para evitar referencias colgantes. El recolector de basura de Java se encargará de liberar la memoria.

Para eliminar el último libro, recorremos la lista hasta el penúltimo nodo, que es aquel cuyo siguiente apunta al último nodo (que a su vez apunta a null). Luego, hacemos que el siguiente del penúltimo nodo sea null, convirtiéndolo en el nuevo último nodo. Si la lista solo tiene un elemento, simplemente hacemos que la cabeza sea null.

Eliminar un libro en una posición específica requiere buscar el nodo anterior al que queremos eliminar, para luego conectar su siguiente con el siguiente del nodo a eliminar. Si queremos eliminar el primer libro, reutilizamos el método de eliminar al principio. También comprobamos que el índice esté dentro de los límites de la lista para evitar errores.

Aquí un ejemplo simplificado de cómo podría quedar la clase Lista con algunos de estos métodos:

public class Lista {
    private class Nodo {
        Libro libro;
        Nodo siguiente;

        Nodo(Libro libro) {
            this.libro = libro;
            this.siguiente = null;
        }
    }

    private Nodo cabeza;
    private int longitud;

    public Lista() {
        cabeza = null;
        longitud = 0;
    }

    public void insertarAlPrincipio(Libro libro) {
        Nodo nuevoNodo = new Nodo(libro);
        nuevoNodo.siguiente = cabeza;
        cabeza = nuevoNodo;
        longitud++;
    }

    public void insertarAlFinal(Libro libro) {
        Nodo nuevoNodo = new Nodo(libro);
        if (cabeza == null) {
            cabeza = nuevoNodo;
        } else {
            Nodo puntero = cabeza;
            while (puntero.siguiente != null) {
                puntero = puntero.siguiente;
            }
            puntero.siguiente = nuevoNodo;
        }
        longitud++;
    }

    public void insertarDespuesDe(int n, Libro libro) {
        Nodo nuevoNodo = new Nodo(libro);
        if (cabeza == null) {
            cabeza = nuevoNodo;
        } else {
            Nodo puntero = cabeza;
            int contador = 0;
            while (contador < n && puntero.siguiente != null) {
                puntero = puntero.siguiente;
                contador++;
            }
            nuevoNodo.siguiente = puntero.siguiente;
            puntero.siguiente = nuevoNodo;
        }
        longitud++;
    }

    public Libro obtenerLibro(int n) {
        if (cabeza == null) return null;
        Nodo puntero = cabeza;
        int contador = 0;
        while (contador < n && puntero != null) {
            puntero = puntero.siguiente;
            contador++;
        }
        if (puntero == null) return null;
        return puntero.libro;
    }

    public int contar() {
        return longitud;
    }

    public boolean estaVacia() {
        return cabeza == null;
    }

    public void eliminarPrincipio() {
        if (cabeza != null) {
            Nodo temp = cabeza;
            cabeza = cabeza.siguiente;
            temp.siguiente = null;
            longitud--;
        }
    }

    public void eliminarUltimo() {
        if (cabeza == null) return;
        if (cabeza.siguiente == null) {
            cabeza = null;
        } else {
            Nodo puntero = cabeza;
            while (puntero.siguiente.siguiente != null) {
                puntero = puntero.siguiente;
            }
            puntero.siguiente = null;
        }
        longitud--;
    }

    public void eliminarEnPosicion(int n) {
        if (cabeza == null || n < 0 || n >= longitud) return;
        if (n == 0) {
            eliminarPrincipio();
            return;
        }
        Nodo puntero = cabeza;
        int contador = 0;
        while (contador < n - 1) {
            puntero = puntero.siguiente;
            contador++;
        }
        Nodo temp = puntero.siguiente;
        puntero.siguiente = temp.siguiente;
        temp.siguiente = null;
        longitud--;
    }
}

Con esta estructura podemos manejar una lista enlazada de libros, insertando y eliminando elementos en distintas posiciones, y obteniendo información útil como el tamaño de la lista o un libro en particular. La gestión de memoria la realiza Java automáticamente, por lo que no necesitamos preocuparnos por liberar nodos manualmente. Esto nos permite centrarnos en la lógica de la lista y en cómo enlazar correctamente los nodos para mantener la integridad de la estructura.

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