Fundamentos de los Algoritmos de Visita
El procesamiento de nodos en un árbol binario depende del orden en que se accede a la raíz relativa a sus hijos. Existen patrones estandarizados:
- Paso Primero (Preorden): Se evalúa el nodo padre antes de sus descendientes (Raíz → Izquierda → Derecha).
- Paso Medio (Inorden): Se recorre primero el subárbol izquierdo, luego se centra en el nodo actual y finalmenet se aborda la rama derecha (Izquierda → Raíz → Derecha).
- Paso Último (Posorden): Los descendientes se procesan completamente antes de visitar la raíz (Izquierda → Derecha → Raíz).
Definición de Estructura y Clases Base
A continuación, se presenta una implementación modular donde se define el nodo individual y una clase contenedora para gestionar las operaciones. Se han utilizado nombres de variables más descriptivos y se ha implementado la lógica de retorno en lugar de solo imprimir.
class NodoArbol: def init(self, dato=None): self.valor = dato self.izquierdo = None self.derecho = None
class ArbolBinario: def init(self, raiz=NodoArbol()): self.raiz = raiz
def vacio(self) -> bool:
return self.raiz is None
def preOrden(self, n):
"""Recorrido Preorden: Imprime valor, luego recursivamente izquierda y derecha."""
if not n:
return []
resultado = [n.valor]
resultado.extend(self.preOrden(n.izquierdo))
resultado.extend(self.preOrden(n.derecho))
return resultado
def inOrden(self, n):
"""Recorrido Inorden: Recursión izquierda, valor, recursión derecha."""
if not n:
return []
return self.inOrden(n.izquierdo) + [n.valor] + self.inOrden(n.derecho)
def posOrden(self, n):
"""Recorrido Posorden: Recursión izquierda, derecha, luego valor."""
if not n:
return []
return self.posOrden(n.izquierdo) + self.posOrden(n.derecho) + [n.valor]
</div>### Solución Iterativa para Nivel por Nivel
Para obtener el recorrido nivel por nivel (BFS), utilizamos una cola. El proceso consiste en extraer un nodo, registrar su valor y añadir sus hijos inmediatos al final de la cola. Para agrupar por niveles, controlamos la cantidad de elementos presentes en cada iteración del ciclo principal.
<div class="code-block">```
def nivelPorNivel(n):
if not n:
return []
resultado_final = []
cola = deque([n])
while cola:
tamanio_nivel = len(cola)
grupo_actual = []
for _ in range(tamanio_nivel):
nodo = cola.popleft()
grupo_actual.append(nodo.valor)
if nodo.izquierdo:
cola.append(nodo.izquierdo)
if nodo.derecho:
cola.append(nodo.derecho)
resultado_final.append(grupo_actual)
return resultado_final
La versión iterativa utiliza una pila (stack) explícita para simular la llamada recursiva. Primero se desciende hacia la izquierda almacenando los nodos en la pila hasta encontrar un null, luego se extrae para procesar y se dirige hacia la rama derecha.
while pilapila or nodo:
while nodo:
pilapila.append(nodo)
nodo = nodo.izquierdo
nodo = pilapila.pop()
resultado.append(nodo.valor)
nodo = nodo.derecho
return resultado
</div>### Cálculo de Profundidad y Transformación de Estructura
Ciertas proipedades del árbol requieren calcular métricas o modificar la topología. La profundidad máxima es la longitud del camino más largo desde la raíz. La inversión de árboles implica intercambiar sistemáticamente los hijos de cada nodo visitado.
<div class="code-block">```
def calcularProfundidadMaxima(n):
if not n:
return 0
profundidad_izquierda = calcularProfundidadMaxima(n.izquierdo)
profundidad_derecha = calcularProfundidadMaxima(n.derecho) # Corrección: usar hijo derecho
return max(profundidad_izquierda, profundidad_derecha) + 1
def invertirArbol(n):
if not n:
return None
# Intercambio recursivo de hijos
temporal = self.invertirArbol(n.izquierdo)
n.izquierdo = self.invertirArbol(n.derecho)
n.derecho = temporal
return n