Extendemos la base del curso previo de árboles binarios y nos enfocamos ahora en los árboles generales o n-arios, estructuras donde cada nodo puede contar con un número arbitrario de hijos. Todo el análisis se implementa en Python, aprovechando referencias, recolección de basura y las mismas convenciones de tutoriales anteriores.
Este primer tema respalda el vocabulario elemental, contrasta las diferencias con los árboles de dos hijos, expone la terminología que reutilizaremos y ejemplifica las ventajas de trabajar con ramas ilimitadas. También revisamos casos reales donde un árbol general es la elección natural.
Un árbol general es una colección jerárquica de nodos unida por aristas dirigidas sin ciclos, donde cada nodo puede tener cero, uno o muchos hijos. Al igual que en los árboles binarios, existe un nodo raíz único y el resto de los nodos se distribuye en niveles según su distancia a la raíz. La diferencia clave radica en que no imponemos límites a la cantidad de descendientes por nodo.
Para reutilizar lo aprendido, mantenemos el mismo Nodo del curso previo y lo adaptamos a una lista de hijos. En Python trabajaremos con listas (o diccionarios si necesitamos claves), lo que elimina la complejidad de reservar arreglos fijos. También veremos una variante con el patrón left-child right-sibling cuando necesitemos compatibilidad con estructuras heredadas.
class Nodo:
def __init__(self, valor):
self.valor = valor
self.hijos = [] # lista de referencias a nodos hijos
def agregar_hijo(self, nodo_hijo):
if nodo_hijo is None:
return
self.hijos.append(nodo_hijo)
# ejemplo de uso
if __name__ == "__main__":
raiz = Nodo("raiz")
raiz.agregar_hijo(Nodo("A"))
raiz.agregar_hijo(Nodo("B"))
raiz.hijos[0].agregar_hijo(Nodo("A1"))
raiz.hijos[0].agregar_hijo(Nodo("A2"))
El método agregar_hijo apoya la extensión natural de la estructura sin preocuparnos por la liberación manual de memoria; el recolector de basura retirará los nodos no referenciados. Para recorridos recursivos, bastará con iterar sobre hijos.
Aunque ambos comparten la idea de una jerarquía sin ciclos, existen diferencias prácticas que debemos tener presentes desde el diseño:
izquierdo y derecho), mientras que un nodo general usa listas o el esquema hijo-izquierdo/hermano-derecho para sostener cualquier cantidad de hijos.Para evitar ambigüedades, estas son las definiciones que utilizaremos durante todo el tutorial:
raiz como hicimos con los árboles binarios.hijos; cada hijo puede tener a su vez sus propios descendientes.Adoptar árboles generales trae beneficios concretos cuando la cantidad de hijos es variable:
raiz, izquierdo, derecho) y permite adaptar funciones del tutorial de binarios.Los árboles generales son esenciales en varios dominios:
Con estas definiciones y motivaciones sentadas podremos profundizar en las representaciones y algoritmos específicos en los próximos temas.