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
- Antes de buscar 10, predice qué rama elegirás al compararlo con 20.
- Avanza un paso y relaciona la comparación C con el nodo visitado.
- 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
- Prepara una operación y predice qué cambiará.
- Activa Paso a paso antes de ejecutar si quieres ver la traza; sin ese modo obtienes el resultado final.
- Relaciona el dibujo con la línea C resaltada: acaba de ejecutarse. Una condición puede no cambiar ningún nodo.
- 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.
- 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. - 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.
- Elige Cargar valores para añadirlos en orden con resultado final, o Agregar paso a paso para estudiar cada inserción.
- 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);
}