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 C, aprovechando punteros, memoria dinámica 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, mantendremos la idea de un TreeNode pero la ampliaremos a un GeneralNode con dos punteros: uno hacia su primer hijo y otro hacia su hermano inmediato. Este patrón, conocido como left-child right-sibling, simplifica las operaciones al conservar punteros similares a izquierdo y derecho usados en el tutorial anterior.
#include <stdlib.h>
typedef struct GeneralNode {
int valor;
struct GeneralNode *primerHijo;
struct GeneralNode *siguienteHermano;
} GeneralNode;
GeneralNode *crearNodoGeneral(int valor) {
GeneralNode *nodo = malloc(sizeof(GeneralNode));
if (!nodo) {
return NULL;
}
nodo->valor = valor;
nodo->primerHijo = NULL;
nodo->siguienteHermano = NULL;
return nodo;
}
void conectarHijo(GeneralNode *padre, GeneralNode *nuevoHijo) {
if (!padre || !nuevoHijo) {
return;
}
nuevoHijo->siguienteHermano = padre->primerHijo;
padre->primerHijo = nuevoHijo;
}
La función conectarHijo inserta cada nuevo hijo al inicio de la lista de descendientes manteniendo un patrón claro, lo que facilita recorrerlos después con ciclos o llamadas recursivas.
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 puede manejar arreglos, 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.primerHijo; cada hijo puede tener a su vez sus propios descendientes.siguienteHermano y que comparten el mismo padre. El orden de los hermanos define el orden de recorrido.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.