ABB

¿Qué representa este TAD?

Un árbol binario de búsqueda (ABB) organiza valores para encontrarlos mediante comparaciones. Desde cada nodo, los menores quedan a la izquierda y los mayores a la derecha; no admite repetidos.

Prueba este ejemplo

En un ABB vacío carga 20, 10, 30 con Agregar varios. La raíz será 20, con 10 a la izquierda y 30 a la derecha. Buscar 10 debe encontrarlo; Inorden debe mostrar 10, 20, 30.

Qué observar · tres pasos

  1. Antes de buscar 10, predice qué rama elegirás al compararlo con 20.
  2. Avanza un paso y relaciona la comparación C con el nodo visitado.
  3. Al terminar, confirma el resultado. Una búsqueda consulta el árbol: no lo reorganiza ni elimina nodos.

Ir a la visualización e ingresar estos datos

De la idea al resultado

  1. Prepara una operación y predice qué cambiará.
  2. Activa Paso a paso antes de ejecutar si quieres ver la traza; sin ese modo obtienes el resultado final.
  3. Relaciona el dibujo con la línea C resaltada: acaba de ejecutarse. Una condición puede no cambiar ningún nodo.
  4. Lee las pistas de Comprender y las pestañas de Resultados.

Paso anterior / Siguiente paso revisan la misma llamada. Pausar no deshace; cerrar Paso a paso muestra su final sin ejecutarla otra vez. Restablecer TAD (o Reiniciar, según el módulo) borra estructura e historial, no sólo el cursor.

Usa −, +, 100%, Encajar vista y Centrar inicio para acomodar el gráfico. El zoom y el desplazamiento se conservan durante los pasos; la memoria auxiliar es opcional.

Agregar varios valores en esta estructura

Disponible en Pila, Cola, Lista enlazada, Lista circular, ABB, AVL, Rojo-Negro y Montículo binario. En las listas agrega al final. No está disponible para Grafos, Hash, Cola de prioridad ni Sublista; Ordenamiento conserva su propia entrada de arreglo.

  1. Abre Agregar varios en Preparar. Escribe hasta 50 enteros separados por comas, por ejemplo 8, -3, 12. Se permiten espacios y signos; no decimales, posiciones vacías ni una coma final. Rango: −2147483648 a 2147483647.
  2. Revisa cantidad y orden. Se valida la lista completa antes de empezar. ABB, AVL y Rojo-Negro no aceptan repetidos, ni dentro del lote ni respecto al árbol actual. Pila, Cola, listas y Montículo sí los admiten.
  3. Elige Cargar valores para añadirlos en orden con resultado final, o Agregar paso a paso para estudiar cada inserción.
  4. En paso a paso, usa los controles del lote. Reproducir traza sólo reproduce el valor actual; Pausar detiene la reproducción. Al final, pulsa Siguiente valor para aceptar la siguiente inserción, o Finalizar lote al terminar la última.

Al terminar o detener un lote, edita la lista antes de iniciar otro. La vista previa conserva el orden solicitado; el resumen describe ese lote, no sustituye el estado actual tras otra operación o Restablecer TAD.

Detener lote conserva las operaciones ya aceptadas, incluida la actual, y descarta los valores pendientes. No es «deshacer todo». Si falla una operación durante el proceso, las anteriores no se revierten. Si la respuesta es incierta, usa Recargar estado e historial y comprueba qué se guardó antes de volver a cargar valores.

Palabras básicas para leer el dibujo
TAD
Tipo abstracto de dato: los datos y las operaciones permitidas sobre ellos.
Nodo
Elemento que guarda un valor y enlaces a otros elementos.
Puntero o enlace
Referencia que permite llegar a otro nodo. NULL indica que no apunta a un nodo.
Raíz, padre e hijo
La raíz inicia el árbol; un padre se conecta con sus hijos.
Tope, frente y atrás
Tope (TOP) en Pila; frente (FRONT) y atrás (BACK) en Cola son referencias a sus extremos.

Primera práctica de 5 minutos · Copiar, ampliar y exportar · Resolver dudas y errores · Atajos y referencia

Profundizar: invariantes, memoria y complejidad

Guía de aprendizaje

Objetivo: Decidir la rama y justificar los tres casos de eliminación.

Estrategia: Comparar, descender recursivamente y reconectar el subárbol retornado.

Invariante: izquierdo < nodo < derecho en todos los nodos.

Memoria C: Cada nodo se reserva con malloc y se libera al eliminar o limpiar.

Para leer el costo: n es la cantidad de nodos y h la altura. O(...) describe crecimiento del trabajo, no tiempo de reproducción.

Complejidad: Buscar, insertar y eliminar dependen de altura h; h puede ser n. Recorridos, altura, contar hojas, validar y liberar visitan los nodos aplicables.

Errores frecuentes

  • Confundir ABB con árbol balanceado.
  • Olvidar reconectar el retorno recursivo.
Glosario jerárquico
Raíz
Nodo sin padre.
Hoja
Nodo sin hijos.
Altura
En ABB, AVL y el auxiliar de Rojo-Negro se cuentan niveles: árbol vacío 0, hoja 1. Revisa la convención de la función que estudias.
Profundidad
Distancia desde la raíz.
FE
Altura del subárbol derecho menos altura del izquierdo.
Rotación
Cambio local de enlaces que conserva el orden.
Recoloreo
Cambio de colores para reparar reglas rojo-negro.
Black-height
Cantidad de nodos negros por camino hasta NIL.
Heapify
Proceso de restaurar la propiedad de heap.

Teclado y accesibilidad

En la visualización, usa → para avanzar un paso, ← para retroceder, Inicio para volver al comienzo, Fin para ir al último paso y Espacio para pausar la reproducción. Los estados y explicaciones también se presentan con texto, no solo con color.

Alcance de esta pantalla

Usa las operaciones disponibles en el selector. Los auxiliares C pueden no tener un botón propio.

Referencia de operaciones y datos de entrada

Operaciones de la aplicación y datos

Altura altura
Sin datos adicionales.
Buscar buscar
Valor (entero)
Contar hojas contar_hojas
Sin datos adicionales.
Eliminar eliminar
Valor (entero)
Inorden inorden
Sin datos adicionales.
Insertar insertar
Valor (entero)
Limpiar limpiar
Sin datos adicionales.
Máximo maximo
Sin datos adicionales.
Mínimo minimo
Sin datos adicionales.
Postorden postorden
Sin datos adicionales.
Preorden preorden
Sin datos adicionales.
Validar validar
Sin datos adicionales.

Los métodos C siguientes pueden incluir helpers, utilidades sin botón propio y llamadores equivalentes. Un bloque con varias funciones no cambia el nombre de la operación de la aplicación. Las vistas de memoria usan identidades simbólicas; tras free, sus registros históricos no son punteros utilizables.

Ejecutar operación crea una llamada; Anterior/Siguiente recorren la misma traza. Cerrar y reactivar Paso a paso no vuelven a ejecutar. Las consultas completadas pueden conservarse en el historial o journal aunque no muten la estructura; los rechazos no agregan llamadas exitosas. Restablecer TAD (o Reiniciar, según el módulo) borra la estructura y su historial.

Referencia avanzada por operación

Abre sólo el tema que estás estudiando. Estos detalles distinguen el contrato C, su representación visual y las funciones auxiliares de la aplicación.

Orden del árbol
  • Árbol binario de búsqueda sin duplicados: todo valor menor va al subárbol izquierdo y todo valor mayor al derecho.
  • En la simulación revisa la ruta de comparaciones y confirma que la propiedad de orden se preserve después de cada inserción o eliminación.
Buscar
  • Buscar retorna un puntero prestado o NULL en C; la interfaz expone encontrado o no encontrado como booleano, sin error por ausencia.
  • El llamador equivalente mostrado contextualiza esa conversión y no agrega otro método al C/H descargado.
Mínimo y máximo
  • Mínimo y máximo recorren enlaces con while, sin recursión ni mutación; retornan un alias prestado.
  • En C, árbol vacío retorna NULL; el wrapper consulta el TAD y convierte ese retorno en un error de interfaz.
Altura y llamadas recursivas
  • En ABB, altura cuenta niveles: vacío 0 y hoja 1.
  • altIzq y altDer son locales int de cada invocación; durante su inicializador recursivo están en ámbito, sin inicializar.
  • El padre conserva sus locales mientras espera al hijo.
  • La altura visita todo el árbol en O(n), con O(h) marcos recursivos, sin cambiar enlaces ni imprimir.
Insertar: retornos y entradas
  • La interfaz rechaza duplicados y eliminaciones ausentes; el TAD C conserva el árbol en esos casos.
  • Asigna a la raíz el retorno de insertar/eliminar.
Limpiar y liberar memoria
  • liberarArbol recibe la raíz por valor: después de liberar, el llamador debe ponerla a NULL.
  • Durante Limpiar, free termina primero las vidas de hijos y después del padre; sus alias se muestran como identidades históricas con valor indeterminado, nunca como direcciones utilizables.
  • El SVG representa reservas vivas y no afirma que el C haya puesto sus enlaces a NULL.
  • El retorno es void y la asignación NULL del main es una instrucción posterior.
Eliminar y sucesor
  • Durante Eliminar, la llamada recursiva no publica enlaces futuros: el retorno se asigna después.
  • Con dos hijos se conserva la reserva encontrada y se copia el valor del sucesor; ambas reservas existen temporalmente con ese valor.
  • El helper minimo tiene su propio ámbito; temp se inicializa al retornar.
  • free termina solo la reserva retirada; sus alias son históricos inutilizables.
Recorridos y funciones auxiliares
  • Los recorridos C imprimen cada entero seguido de un espacio, sin salto final.
  • Contar hojas y Validar usan auxiliares mostrados en la aplicación que no están declarados en el C/H descargado.
Contar hojas
  • Contar hojas retorna 0 para NULL y 1 para un nodo sin hijos; en otro caso suma los conteos de ambos subárboles sin mutación ni printf.
  • C no fija cuál llamada de esa suma se evalúa primero: un orden mostrado u observado es una opción permitida, no una garantía del lenguaje.
  • Los resultados parciales son operandos de la expresión, no variables locales declaradas.
  • El main mostrado con Contar hojas incluye stdio.h, tad_abb.h y el auxiliar canónico una sola vez; compílalo junto a tad_abb.c.
  • Imprime el conteo calculado, conserva consultas repetidas y las recupera al recargar sin volver a ejecutarlas para reconstruir el árbol.
Validar y límites
  • Validar ABB usa límites estrictos opcionales con indicadores enteros: la llamada inicial omite ambos límites y admite INT_MIN/INT_MAX.
  • No usa centinelas ni +/-1.
  • Cada hijo hereda los límites de sus ancestros; igualdad o duplicado devuelve 0.
  • NULL devuelve 1.
  • El cortocircuito omite límites ausentes y no visita el subárbol derecho si el izquierdo falla.
  • Es consulta sin mutación ni printf; cada marco conserva sus parámetros.
  • El main incluye el auxiliar una sola vez y calcula cada validación, sin imprimir una respuesta almacenada de la interfaz.
  • Consultas repetidas sobreviven a recarga sin volver a ejecutar esas operaciones del historial al reconstruir.

Código fuente completo del TAD

Descarga el archivo C principal de ABB y su encabezado para estudiarlo o compilarlo en tu equipo.

Referencia: estructura del TAD en C
typedef struct ABBNodo {
    int valor; /**< Dato entero almacenado. */
    struct ABBNodo *izquierdo; /**< Hijo izquierdo. */
    struct ABBNodo *derecho; /**< Hijo derecho. */
} ABBNodo;

Código C y llamadores equivalentes

Insertar · código C

Inserta respetando reglas de orden/balance del TAD y actualiza punteros estructurales necesarios.

/**
 * @brief Inserta un valor en el árbol binario de búsqueda.
 * @param nodo Puntero a la raíz del árbol.
 * @param valor Valor entero.
 * @return Raíz actualizada; NULL si el árbol estaba vacío y malloc falla.
 * @note Si falla la reserva en un subárbol, se conserva la raíz existente sin insertar el valor.
  * @note El arbol debe ser un ABB valido y aciclico. Un duplicado conserva la misma raiz sin reservar otro nodo. Asigne el retorno a la raiz del llamador; los enlaces internos se modifican. El nuevo nodo se inicializa antes de enlazarlo.
 */
ABBNodo* abb_insertar(ABBNodo* nodo, int valor) {
    if (nodo == NULL) {
        ABBNodo* nuevo = malloc(sizeof *nuevo);
        if (nuevo == NULL) {
            return NULL;
        }
        nuevo->valor = valor;
        nuevo->izquierdo = nuevo->derecho = NULL;
        return nuevo;
    }
    if (valor < nodo->valor)
        nodo->izquierdo = abb_insertar(nodo->izquierdo, valor);
    else if (valor > nodo->valor)
        nodo->derecho = abb_insertar(nodo->derecho, valor);
    return nodo;
}
Eliminar · código C

Localiza el objetivo y aplica el caso de borrado correspondiente (hoja, un hijo, dos hijos o rebalanceo).

/**
 * @brief Elimina un valor del árbol binario de búsqueda.
 * @param nodo Puntero a la raíz del árbol.
 * @param valor Valor entero.
 * @return Puntero a la raíz actualizada.
  * @note Un valor ausente conserva la raiz. Asigne el retorno a la raiz del llamador. Con cero o un hijo se libera el nodo encontrado y se retorna el reemplazo. Con dos hijos se copia el valor del sucesor, se conserva la reserva del nodo encontrado y se elimina el sucesor. Los alias al nodo liberado dejan de ser validos.
 */
ABBNodo* abb_eliminar(ABBNodo* nodo, int valor) {
    if (nodo == NULL) return nodo;
    if (valor < nodo->valor)
        nodo->izquierdo = abb_eliminar(nodo->izquierdo, valor);
    else if (valor > nodo->valor)
        nodo->derecho = abb_eliminar(nodo->derecho, valor);
    else {
        if (nodo->izquierdo == NULL) {
            ABBNodo* temp = nodo->derecho;
            free(nodo);
            return temp;
        } else if (nodo->derecho == NULL) {
            ABBNodo* temp = nodo->izquierdo;
            free(nodo);
            return temp;
        }
        ABBNodo* temp = abb_encontrarMinimo(nodo->derecho);
        nodo->valor = temp->valor;
        nodo->derecho = abb_eliminar(nodo->derecho, temp->valor);
    }
    return nodo;
}
Buscar · código C

Navega por comparaciones hasta encontrar el valor o concluir que no existe.

/**
 * @brief Busca un valor en el árbol binario de búsqueda.
 * @param nodo Puntero a la raíz del árbol.
 * @param valor Valor entero.
 * @return Puntero al nodo encontrado o NULL si no existe.
  * @note Consulta sin mutacion. El retorno es un alias prestado de un nodo existente, no una copia ni una reserva nueva. NULL tambien representa un arbol vacio.
 */
ABBNodo* abb_buscar(ABBNodo* nodo, int valor) {
    if (nodo == NULL || nodo->valor == valor)
        return nodo;
    if (valor < nodo->valor)
        return abb_buscar(nodo->izquierdo, valor);
    else
        return abb_buscar(nodo->derecho, valor);
}
Mínimo · código C

Avanza por la rama izquierda hasta el último nodo para obtener el menor valor del subárbol.

/**
 * @brief Encuentra el nodo con el valor mínimo en el árbol.
 * @param nodo Puntero a la raíz del árbol.
 * @return Puntero al nodo con el valor mínimo, o NULL si el árbol está vacío.
  * @note Consulta sin mutacion: sigue enlaces izquierdos y retorna un alias prestado, no una reserva nueva. NULL representa el arbol vacio.
 */
ABBNodo* abb_encontrarMinimo(ABBNodo* nodo) {
    if (nodo == NULL) {
        return NULL;
    }

    while (nodo->izquierdo != NULL)
        nodo = nodo->izquierdo;
    return nodo;
}
Máximo · código C

Avanza por la rama derecha hasta el último nodo para obtener el mayor valor del subárbol.

/**
 * @brief Encuentra el nodo con el valor máximo en el árbol.
 * @param nodo Puntero a la raíz del árbol.
 * @return Puntero al nodo con el valor máximo, o NULL si el árbol está vacío.
  * @note Consulta sin mutacion: sigue enlaces derechos y retorna un alias prestado, no una reserva nueva. NULL representa el arbol vacio.
 */
ABBNodo* abb_encontrarMaximo(ABBNodo* nodo) {
    while (nodo != NULL && nodo->derecho != NULL)
        nodo = nodo->derecho;
    return nodo;
}
Altura · código C

Calcula la altura estructural a partir de la profundidad máxima de sus ramas.

/**
 * @brief Calcula la abb_altura del árbol binario de búsqueda.
 * @param nodo Puntero a la raíz del árbol.
 * @return Altura del árbol (número de niveles).
  * @note Cuenta niveles: NULL retorna cero y una hoja retorna uno. No cuenta aristas, no modifica el arbol y recorre ambos subarboles.
 */
int abb_altura(ABBNodo* nodo) {
    if (nodo == NULL)
        return 0;
    int altIzq = abb_altura(nodo->izquierdo);
    int altDer = abb_altura(nodo->derecho);
    return (altIzq > altDer ? altIzq : altDer) + 1;
}
Contar hojas (auxiliar) · código C

Cuenta nodos sin hijos para medir terminales del árbol.

/**
 * @brief Cuenta hojas sin modificar el arbol ni imprimir.
 * @param nodo Raiz prestada del subarbol, o NULL.
 * @return 0 para NULL, 1 para una hoja, o la suma de ambos subarboles.
 * @note Helper mostrado por la aplicacion; no incluido en el C/H descargado.
 * C no fija el orden de evaluacion de las dos llamadas sumadas.
 * No declara locales para sus resultados parciales; son operandos de la expresion.
 * Tiempo O(n), pila recursiva O(h); no reserva ni libera nodos.
 */
int abb_contarHojas(ABBNodo* nodo) {
    if (nodo == NULL) {
        return 0;
    }
    if (nodo->izquierdo == NULL && nodo->derecho == NULL) {
        return 1;
    }
    return abb_contarHojas(nodo->izquierdo) + abb_contarHojas(nodo->derecho);
}
Inorden · código C

Recorrido izquierda-raíz-derecha; en ABB produce valores ordenados de menor a mayor.

/**
 * @brief Realiza un recorrido inorden del árbol.
 * @param nodo Puntero a la raíz del árbol.
  * @note Imprime izquierdo, raiz y derecho en stdout con formato "%d " por nodo, incluido el espacio final y sin agregar salto de linea. NULL no imprime nada. No modifica enlaces ni reserva memoria.
 */
void abb_inorden(ABBNodo* nodo) {
    if (nodo != NULL) {
        abb_inorden(nodo->izquierdo);
        printf("%d ", nodo->valor);
        abb_inorden(nodo->derecho);
    }
}
Preorden · código C

Recorrido raíz-izquierda-derecha; útil para serializar la forma del árbol.

/**
 * @brief Realiza un recorrido preorden del árbol.
 * @param nodo Puntero a la raíz del árbol.
  * @note Imprime raiz, izquierdo y derecho en stdout con formato "%d " por nodo, incluido el espacio final y sin agregar salto de linea. NULL no imprime nada. No modifica enlaces ni reserva memoria.
 */
void abb_preorden(ABBNodo* nodo) {
    if (nodo != NULL) {
        printf("%d ", nodo->valor);
        abb_preorden(nodo->izquierdo);
        abb_preorden(nodo->derecho);
    }
}
Postorden · código C

Recorrido izquierda-derecha-raíz; usado en liberación segura de memoria.

/**
 * @brief Realiza un recorrido postorden del árbol.
 * @param nodo Puntero a la raíz del árbol.
  * @note Imprime izquierdo, derecho y raiz en stdout con formato "%d " por nodo, incluido el espacio final y sin agregar salto de linea. NULL no imprime nada. No modifica enlaces ni reserva memoria.
 */
void abb_postorden(ABBNodo* nodo) {
    if (nodo != NULL) {
        abb_postorden(nodo->izquierdo);
        abb_postorden(nodo->derecho);
        printf("%d ", nodo->valor);
    }
}
Validar · código C

Consulta las reglas indicadas en la referencia avanzada de este TAD. No modifica ni repara la estructura; observa las condiciones que hacen devolver verdadero o falso.

/**
 * @brief Valida orden ABB estricto con limites opcionales, sin mutacion.
 * @param nodo Raiz del subarbol finito y aciclico; NULL admitido.
 * @param hay_minimo Indicador de limite inferior presente; cero lo omite.
 * @param minimo Limite inferior exclusivo, solo comparado si hay_minimo.
 * @param hay_maximo Indicador de limite superior presente; cero lo omite.
 * @param maximo Limite superior exclusivo, solo comparado si hay_maximo.
 * @return 1 si el subarbol respeta todos los limites; 0 si no.
 * @note Auxiliar didactico de la aplicacion; no exportado por el C/H del TAD.
 * La llamada inicial usa 0,0,0,0: INT_MIN e INT_MAX son claves validas.
 * No usa sentinelas fuera de int ni suma/resta uno. Los limites presentes
 * rechazan igualdad y duplicados. El cortocircuito omite limites ausentes
 * y omite el subarbol derecho cuando el izquierdo resulta invalido.
 */
int abb_validar_rango(ABBNodo* nodo, int hay_minimo, int minimo, int hay_maximo, int maximo) {
    if (nodo == NULL) {
        return 1;
    }
    if ((hay_minimo && nodo->valor <= minimo) || (hay_maximo && nodo->valor >= maximo)) {
        return 0;
    }
    if (!abb_validar_rango(nodo->izquierdo, hay_minimo, minimo, 1, nodo->valor)) {
        return 0;
    }
    if (!abb_validar_rango(nodo->derecho, 1, nodo->valor, hay_maximo, maximo)) {
        return 0;
    }
    return 1;
}
Limpiar · código C

Recorre la estructura liberando todos los nodos y deja el puntero raíz en estado nulo para reinicio seguro.

/**
 * @brief Libera toda la memoria del árbol (abb_postorden).
 * @param nodo Raíz del árbol o subárbol a liberar.
  * @note Libera cada nodo en orden izquierdo, derecho y raiz; NULL no hace nada. El parametro se recibe por valor: no pone a NULL la raiz del llamador. Despues de la llamada, asigne NULL a esa raiz y no use los alias a las reservas liberadas.
 */
void abb_liberarArbol(ABBNodo* nodo) {
    if (nodo == NULL) return;
    abb_liberarArbol(nodo->izquierdo);
    abb_liberarArbol(nodo->derecho);
    free(nodo);
}

Ir a la visualización