4 - Nodo base en Python

Elementos fundamentales

El diseño del nodo y las referencias de control determinan la flexibilidad y seguridad de cualquier lista enlazada. Entender cómo declararlos en Python, cómo exponerlos dentro de clases y cómo organizar el archivo es un paso obligado antes de implementar operaciones complejas.

4.1 Definición de la clase base

Partimos de una clase que represente el valor almacenado y el enlace disponible. Adaptamos los campos según el tipo de lista; aquí mostramos la forma más común.

class Nodo:
    def __init__(self, valor):
        self.valor = valor
        self.sig = None

El nodo guarda el dato y la referencia al siguiente. El tipo de valor puede ser cualquier objeto de Python. Inicializamos sig en None para indicar que el nodo aún no está enlazado.

4.2 Referencia a cabeza (head)

La referencia cabeza es la entrada oficial a la lista. Se almacena fuera del nodo para mantener control sobre el conjunto completo.

# listas_enlazadas.py

class ListaSimple:
    def __init__(self):
        self.cabeza = None

    def insertar_inicio(self, valor):
        nuevo = Nodo(valor)
        nuevo.sig = self.cabeza
        self.cabeza = nuevo

La referencia a cabeza permite insertar y eliminar al inicio sin recorrer todo. Siempre debe inicializarse en None y actualizarse cada vez que la lista queda vacía.

4.3 Referencia a cola (tail)

Agregar una referencia cola (tail) acelera las inserciones al final. Se utiliza junto con cabeza cuando la estructura necesita operar en ambos extremos.

class ListaConCola:
    def __init__(self):
        self.cabeza = None
        self.cola = None

    def insertar_final(self, valor):
        nuevo = Nodo(valor)
        if self.cola is None:
            self.cabeza = self.cola = nuevo
            return
        self.cola.sig = nuevo
        self.cola = nuevo

La referencia a cola evita recorrer la lista para insertar al final. La condición especial es cuando la lista está vacía: ambas referencias deben apuntar al nuevo nodo.

4.4 Diferencias entre tipos de listas

La clase base se adapta según la variante elegida. A continuación se muestra una comparativa rápida:

Tipo Campos adicionales Ventaja Coste
Simple sig Menor uso de memoria No se puede retroceder
Doble sig, ant Recorridos bidireccionales Duplicación de referencias
Circular sig conectando al inicio Recorridos continuos sin comprobaciones de None Mayor atención para terminar ciclos

4.5 Organización en un archivo Python

En Python podemos mantener el nodo base y las operaciones en un solo archivo para facilitar la prueba rápida. Si el proyecto crece, basta con dividir en módulos, pero la estructura inicial puede ser así:

# listas_enlazadas.py

class Nodo:
    def __init__(self, valor):
        self.valor = valor
        self.sig = None


class Lista:
    def __init__(self):
        self.cabeza = None
        self.cola = None

    def insertar_inicio(self, valor):
        nuevo = Nodo(valor)
        nuevo.sig = self.cabeza
        self.cabeza = nuevo
        if self.cola is None:
            self.cola = nuevo

    def insertar_final(self, valor):
        nuevo = Nodo(valor)
        if self.cola is None:
            self.cabeza = self.cola = nuevo
            return
        self.cola.sig = nuevo
        self.cola = nuevo

    def limpiar(self):
        while self.cabeza:
            siguiente = self.cabeza.sig
            self.cabeza.sig = None
            self.cabeza = siguiente

    def imprimir(self):
        reco = self.cabeza
        while reco:
            print(reco.valor, end=" -> ")
            reco = reco.sig
        print("None")


def main():
    lista = Lista()
    lista.insertar_inicio(10)
    lista.insertar_final(20)
    lista.insertar_final(30)
    lista.imprimir()
    lista.limpiar()


if __name__ == "__main__":
    main()

Flujo sugerido para probar: crear la lista (lista = Lista()), insertar 10 al inicio y luego 20 y 30 al final, y finalmente llamar a lista.imprimir() para ver 10 -> 20 -> 30 -> None. Al terminar, lista.limpiar() recorre la estructura, corta cada referencia sig y deja cabeza en None, de modo que el recolector pueda liberar los nodos sin referencias activas.

Con este esquema mantenemos en un solo lugar el nodo base, las referencias cabeza/cola y las operaciones esenciales. Más adelante se puede separar en módulos si aparece nueva funcionalidad.