En Python podemos implementar una pila con una lista (o deque) o con una estructura enlazada propia. Ambas ofrecen operaciones O(1) en el tope, pero difieren en memoria, previsibilidad y cómo manejan el crecimiento. Elegir a tiempo evita refactors innecesarios.
| Criterio | Lista / deque | Lista enlazada |
|---|---|---|
| Memoria | Contigua; overhead interno pequeño | Nodo a nodo; un enlace extra por elemento |
| Crecimiento | Dinámico; deque evita realocaciones grandes |
Bajo demanda, solo limitado por RAM |
| Operaciones | append/pop O(1) amortizado; deque O(1) firme |
push/pop O(1) siempre |
| Complejidad de código | Mínima; sin clases extra | Requiere nodos y manejo de referencias |
| Casos ideales | Historias acotadas, cargas intensivas, simplicidad | Tamaños impredecibles, fines didácticos, evitar bloques contiguos |
Podemos mantener la misma interfaz y alternar entre implementaciones según el escenario. El siguiente ejemplo define una función que recibe cualquier pila que implemente push, pop y esta_vacia:
def procesar(pila):
for valor in (1, 2, 3):
pila.push(valor)
while not pila.esta_vacia():
print("Pop:", pila.pop())
# Con lista
from collections import deque
class PilaLista:
def __init__(self):
self._datos = deque()
def push(self, v):
self._datos.append(v)
def pop(self):
return self._datos.pop()
def esta_vacia(self):
return not self._datos
# Con nodos enlazados
class Nodo:
def __init__(self, valor, sig=None):
self.valor = valor
self.sig = sig
class PilaEnlazada:
def __init__(self):
self.tope = None
def push(self, v):
self.tope = Nodo(v, self.tope)
def pop(self):
if not self.tope:
raise IndexError("Pila vacia")
valor = self.tope.valor
self.tope = self.tope.sig
return valor
def esta_vacia(self):
return self.tope is None
procesar(PilaLista())
procesar(PilaEnlazada())
Mientras la interfaz se conserve, el código consumidor no se entera de la representación. Esto permite iniciar con listas y migrar a nodos sin tocar la lógica de negocio.
pop(0) en lugar de pop() (desplaza todo); olvidar que deque ofrece append/pop constantes.pop/peek; perder la referencia al tope antes de enlazar el nuevo nodo.queue.LifoQueue, que incorpora locks y límite opcional.La elección puede ser incremental: comienza con list/deque y cambia a nodos solo si los requisitos lo demandan.