Recorrido preorden de árbol binario en C: ejercicio resuelto

Recorrido preorden de árbol binario en C: ejercicio resuelto

Si buscas recorrido preorden de árbol binario en C ejercicio resuelto, aquí tienes las dos implementaciones canónicas: la versión recursiva (natural y concisa) y la iterativa con pila explícita (necesaria para árboles muy profundos que agotarían la pila del sistema).

En preorden el orden de visita es raíz → hijo izquierdo → hijo derecho (NLR: Node-Left-Right).

Enunciado

Dado el árbol:

1
2
3
4
5
        1
       / \
      2   3
     / \   \
    4   5   6

Imprime los nodos en orden preorden de forma recursiva e iterativa.

Solución en C

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
#include <stdlib.h>

typedef struct Nodo {
    int dato;
    struct Nodo *izq, *der;
} Nodo;

Nodo *nuevo(int dato) {
    Nodo *n = malloc(sizeof(Nodo));
    n->dato = dato; n->izq = n->der = NULL;
    return n;
}

/* --- Versión recursiva --- */
void preorden_rec(const Nodo *n) {
    if (!n) return;
    printf("%d ", n->dato);
    preorden_rec(n->izq);
    preorden_rec(n->der);
}

/* --- Versión iterativa con pila --- */
#define MAX_PILA 64
void preorden_iter(const Nodo *raiz) {
    if (!raiz) return;
    const Nodo *pila[MAX_PILA];
    int tope = 0;
    pila[tope++] = raiz;

    while (tope > 0) {
        const Nodo *n = pila[--tope];
        printf("%d ", n->dato);
        /* Apilar derecho primero para procesar izquierdo antes */
        if (n->der) pila[tope++] = n->der;
        if (n->izq) pila[tope++] = n->izq;
    }
}

void liberar(Nodo *n) {
    if (!n) return;
    liberar(n->izq);
    liberar(n->der);
    free(n);
}

int main(void) {
    Nodo *raiz = nuevo(1);
    raiz->izq  = nuevo(2);
    raiz->der  = nuevo(3);
    raiz->izq->izq = nuevo(4);
    raiz->izq->der = nuevo(5);
    raiz->der->der = nuevo(6);

    printf("Recursivo: "); preorden_rec(raiz);  printf("\n");
    printf("Iterativo: "); preorden_iter(raiz); printf("\n");

    liberar(raiz);
    return 0;
}

Resultado esperado

1
2
Recursivo: 1 2 4 5 3 6 
Iterativo: 1 2 4 5 3 6 

Errores frecuentes

  • En la versión iterativa, apilar el hijo izquierdo antes que el derecho: como la pila es LIFO, hay que apilar derecho primero para que izquierdo se procese antes.
  • No comprobar NULL antes de acceder a los hijos: n->izq->dato sin verificar que n->izq != NULL provoca segmentation fault.
  • No liberar la memoria del árbol: cada nodo se asigna con malloc y debe liberarse con free recorriendo el árbol en postorden.
  • Confundir preorden con inorden: preorden visita la raíz primero (NLR); inorden visita la raíz entre los hijos (LNR).

Aplicación práctica

El recorrido preorden se usa para serializar/copiar un árbol (el orden de inserción reconstruye la misma estructura), para evaluar expresiones en notación prefija (árboles de expresión) y para imprimir la jerarquía de directorios de un sistema de ficheros.

Siguiente ejercicio recomendado

Práctica guiada y libro completo

Si quieres una ruta completa con progresión real de dificultad:

FAQ

¿Cuál es la diferencia entre preorden, inorden y postorden?

Los tres recorren los mismos nodos pero en distinto orden:

  • Preorden (NLR): raíz primero, luego subárbol izquierdo, luego derecho.
  • Inorden (LNR): subárbol izquierdo, raíz, subárbol derecho. En un BST produce los valores ordenados.
  • Postorden (LRN): subárboles primero, raíz al final. Útil para liberar memoria.

¿Cuándo usar la versión iterativa frente a la recursiva?

La versión recursiva es más legible y suficiente para árboles de profundidad razonable. La iterativa es necesaria cuando el árbol puede ser muy profundo (miles de niveles) y la pila del sistema no es suficiente. En producción, los árboles auto-balanceados como AVL o Red-Black tienen profundidad O(log n), lo que hace la recursión segura.

¿El recorrido preorden es único para un árbol dado?

Sí: para un árbol binario dado, el preorden es único. Sin embargo, conocer solo el preorden no es suficiente para reconstruir el árbol; se necesita también el inorden (o marcar los nodos NULL explícitamente en la serialización).