Laboratorio de árboles y montículos en C

Rojo-Negro

Árbol rojo-negro auto-balanceado.

Abrir guía de Rojo-Negro

1 Preparar

Los ejemplos construyen el estado mediante operaciones públicas reales.

2 Predecir

Formula una hipótesis antes de revelar el siguiente frame canónico.

Progreso conceptual de esta sesión: 0 aciertos de 0 intentos.

3 Ejecutar y visualizar

5 Relacionar con C

Codigo C: Insertar

/**
 * @brief Devuelve el rbt_abuelo de un nodo.
 * @param n Nodo dado.
 * @return Puntero al rbt_abuelo o NULL si no existe.
 */
RBT rbt_abuelo(RBT n) {
    if ((n != NULL) && (n->padre != NULL))
        return n->padre->padre;
    else
        return NULL;
}

/**
 * @brief Devuelve el tío de un nodo (hermano del padre).
 * @param n Nodo dado.
 * @return Puntero al tío o NULL si no existe.
 */
RBT rbt_tio(RBT n) {
    RBT a = rbt_abuelo(n);
    if (a == NULL)
        return NULL;
    if (n->padre == a->izq)
        return a->der;
    else
        return a->izq;
}

/**
 * @brief Rotación simple derecha.
 * @param r Referencia a la raíz del árbol.
 * @param nodoRBT Nodo sobre el que se aplica la rotación.
 */
void rbt_rotar_dcha(RBT *r, RBT nodoRBT) {
    if (r == NULL || nodoRBT == NULL || nodoRBT->izq == NULL) {
        return;
    }

    RBT padre = nodoRBT->padre;
    RBT A = nodoRBT;
    RBT B = A->izq;
    RBT C = B->der;
    if (padre != NULL) {
        if (padre->der == A)
            padre->der = B;
        else
            padre->izq = B;
    } else
        *r = B;

    A->izq = C;
    B->der = A;
    A->padre = B;
    if (C)
        C->padre = A;
    B->padre = padre;
}

/**
 * @brief Rotación simple izquierda.
 * @param r Referencia a la raíz del árbol.
 * @param nodoRBT Nodo sobre el que se aplica la rotación.
 */
void rbt_rotar_izda(RBT *r, RBT nodoRBT) {
    if (r == NULL || nodoRBT == NULL || nodoRBT->der == NULL) {
        return;
    }

    RBT padre = nodoRBT->padre;
    RBT A = nodoRBT;
    RBT B = A->der;
    RBT C = B->izq;
    if (padre != NULL) {
        if (padre->der == A)
            padre->der = B;
        else
            padre->izq = B;
    } else
        *r = B;

    A->der = C;
    B->izq = A;
    A->padre = B;
    if (C)
        C->padre = A;
    B->padre = padre;
}

/**
 * @brief Caso 5 de inserción: rotación final y recoloreo.
 * @param n Nodo insertado.
 * @param arbol Referencia a la raíz del árbol.
 */
void rbt_insercion_caso5(RBT n, RBT *arbol) {
    RBT a = rbt_abuelo(n);
    n->padre->rbt_color = NEGRO;
    a->rbt_color = ROJO;
    if ((n == n->padre->izq) && (n->padre == a->izq)) {
        rbt_rotar_dcha(arbol, a);
    } else {
        rbt_rotar_izda(arbol, a);
    }
}

/**
 * @brief Caso 4 de inserción: ajuste para alinear nodo, padre y rbt_abuelo.
 * @param n Nodo insertado (puede cambiar tras rotación).
 * @param arbol Referencia a la raíz del árbol.
 */
void rbt_insercion_caso4(RBT n, RBT *arbol) {
    RBT a = rbt_abuelo(n);
    RBT nuevo_n = n;

    if ((n == n->padre->der) && (n->padre == a->izq)) {
        rbt_rotar_izda(arbol, n->padre);
        nuevo_n = n->izq;
    } else if ((n == n->padre->izq) && (n->padre == a->der)) {
        rbt_rotar_dcha(arbol, n->padre);
        nuevo_n = n->der;
    }
    rbt_insercion_caso5(nuevo_n, arbol);
}

/**
 * @brief Caso 3 de inserción: tío rojo o tío negro.
 * @param n Nodo insertado.
 * @param arbol Referencia a la raíz del árbol.
 */
void rbt_insercion_caso3(RBT n, RBT *arbol) {
    RBT t = rbt_tio(n);
    RBT a;

    if ((t != NULL) && (t->rbt_color == ROJO)) {
        n->padre->rbt_color = NEGRO;
        t->rbt_color = NEGRO;
        a = rbt_abuelo(n);
        a->rbt_color = ROJO;
        rbt_insercion_caso1(a, arbol);
    } else {
        rbt_insercion_caso4(n, arbol);
    }
}

/**
 * @brief Caso 2 de inserción: si padre es negro, árbol válido.
 * @param n Nodo insertado.
 * @param arbol Referencia a la raíz del árbol.
 */
void rbt_insercion_caso2(RBT n, RBT *arbol) {
    if (n->padre->rbt_color == NEGRO)
        return;
    else
        rbt_insercion_caso3(n, arbol);
}

/**
 * @brief Caso 1 de inserción: si es raíz, pintar de negro.
 * @param n Nodo insertado.
 * @param arbol Referencia a la raíz del árbol.
 */
void rbt_insercion_caso1(RBT n, RBT *arbol) {
    if (n->padre == NULL)
        n->rbt_color = NEGRO;
    else
        rbt_insercion_caso2(n, arbol);
}

/**
 * @brief Inserta un valor en el árbol Rojo-Negro.
 * @param arbol Referencia a la raíz del árbol.
 * @param dato Valor a rbt_insertar.
 */
void rbt_insertar(RBT *arbol, int dato) {
    if (arbol == NULL) {
        return;
    }

    RBT padre = NULL;
    RBT actual = *arbol;
    while (actual != NULL && dato != actual->nro) {
        padre = actual;
        if (dato < actual->nro)
            actual = actual->izq;
        else if (dato > actual->nro)
            actual = actual->der;
    }
    if (actual != NULL)
        return;
    actual = malloc(sizeof(struct nodoRBT));
    if (actual == NULL) {
        return;
    }
    actual->nro = dato;
    actual->izq = actual->der = NULL;
    actual->padre = padre;
    actual->rbt_color = ROJO;
    if (padre == NULL) {
        *arbol = actual;
    } else if (dato < padre->nro) {
        padre->izq = actual;
    } else if (dato > padre->nro) {
        padre->der = actual;
    }
    rbt_insercion_caso1(actual, arbol);
    printf("\tEl numero ha sido insertado\n");
}

3 Controlar la ejecución

Actual: +0.00x (1.00x real)

Función: — · Profundidad: — · Fase: — · Concepto: —

Paso: 0/0

4 Comprender

Arbol balanceado por reglas de color (rojo/negro) que limitan la altura. Durante la simulacion observa recoloreos y rotaciones para mantener raiz negra, sin rojos consecutivos y con altura negra consistente entre caminos.

Prepara una operación para observar ruta, caso e invariante.

Condición, ruta y caso

Sin frame.

Pila recursiva y retornos

Sin llamadas.

Invariante y evidencia

Sin verificación.

Variables C

Sin variables.

Memoria y enlaces

Sin transición de memoria.

Relaciones estructurales

Sin relaciones.

6 Comparar

Ambos lados reciben copias independientes de la misma entrada inmutable.

Prepara una comparación para estudiar forma, altura, ajustes, costo e invariante.

7 Reflexionar

Consola C (printf)

terminal

Historial

    Estructura del TAD
    typedef struct nodoRBT {
        int nro;                  
        char rbt_color;               
        struct nodoRBT *padre;   
        struct nodoRBT *izq;      
        struct nodoRBT *der;     
    } nodoRBT;
    
    typedef struct nodoRBT *RBT;