AVL
¿Qué representa este TAD?
Un AVL es un árbol de búsqueda que se equilibra para evitar ramas demasiado largas. Usa rotaciones: cambia enlaces sin perder el orden de los valores.
Prueba este ejemplo
En un AVL vacío carga 30, 20, 10 con Agregar paso a paso. Al completar las tres inserciones, una rotación deja 20 como raíz, 10 a su izquierda y 30 a su derecha.
Qué observar · tres pasos
- Antes del tercer valor, observa qué rama está creciendo.
- Usa Siguiente valor sólo cuando termines la traza actual y sigue los enlaces durante la rotación.
- Comprueba el orden y el equilibrio al final, no a mitad de las escrituras. El factor de equilibrio compara las alturas derecha e izquierda.
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: Relacionar altura y FE con LL, RR, LR y RL.
Estrategia: Operar como ABB, actualizar alturas y reparar el primer desequilibrio.
Invariante: Orden ABB y |FE| ≤ 1 por nodo.
Memoria C: Las rotaciones cambian enlaces; no crean ni destruyen nodos.
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: La altura equilibrada limita la búsqueda a O(log n). La implementación de eliminación recalcula alturas mediante recorridos; no se atribuye a ese trabajo el coste de una variante que guarda alturas.
Errores frecuentes
- Rotar según el valor sin calcular FE.
- No actualizar alturas después de rotar.
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
- El TAD no expone información textual de rotaciones realizadas.
Referencia de operaciones y datos de entrada
Operaciones de la aplicación y datos
- Altura
altura - Sin datos adicionales.
- Buscar
buscar - Valor (entero)
- 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.
- 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.
Equilibrio y rotaciones
- Árbol AVL autobalanceado: mantiene factor de equilibrio por nodo en el rango [-1, 1].
- La animación debe mostrar detección del nodo desbalanceado y aplicación de rotaciones (LL, RR, LR, RL) sincronizadas con la línea C que se interpreta.
- Las rotaciones C conservan valores y reservas, reenlazan padres/raíz y actualizan FE como altura(derecho)-altura(izquierdo), sin poner ambos a cero.
- Las simples calculan primero A y luego B con fórmulas O(1); las dobles componen dos simples sin preasignar FE.
- También contemplan hijo equilibrado al eliminar y nieto FE-1/0/1.
- El llamador mantiene factores de ancestros; durante la reconexión y antes de actualizar FE no se debe afirmar un AVL terminado.
Eliminar y liberar
- Eliminar retorna void y no imprime.
- Con dos hijos intercambia el valor con el sucesor y libera su reserva; la reserva encontrada inicialmente puede seguir viva con otro valor.
- Sin hijos o con uno, publica el enlace y el padre del hijo antes de free.
- Los alias de la reserva retirada dejan de ser utilizables.
- Vacío/ausencia son rechazos web; el C deja el árbol intacto.
- El reequilibrio recalcula alturas y puede visitar la nueva raíz del subárbol después de rotar.
Validar por alturas
- Validar muestra un auxiliar de equilibrio por alturas: no revisa orden ABB ni FE almacenado.
- El backend revisa orden y equilibrio por separado.
- NULL retorna 1 en el auxiliar; la primera diferencia fuera de -1..1 corta la recursión.
- Su traza elige altura derecha y después izquierda, aunque C permite otro orden de operandos de la resta.
Historial, main y auxiliares
- El main del historial reproduce consultas exitosas, incluidas repeticiones; recargar conserva esas consultas sin ejecutarlas otra vez.
- Máximo, Inorden y equilibrio por alturas usan los auxiliares mostrados, incluidos una vez en ese programa; no son exportaciones del C/H descargable.
- Inorden imprime valores ascendentes, no avl_verArbol.
- La comprobación de equilibrio por alturas no certifica el FE almacenado.
- Compile el main junto a tad_avl.c; los rechazos se anotan sin ejecutar la llamada fallida.
Código fuente completo del TAD
Descarga el archivo C principal de AVL y su encabezado para estudiarlo o compilarlo en tu equipo.
Referencia: estructura del TAD en C
typedef struct nodoAVL {
int nro; /**< Dato entero almacenado. */
int FE; /**< Factor de equilibrio: altura del hijo derecho menos altura del izquierdo. */
struct nodoAVL *der; /**< Hijo derecho. */
struct nodoAVL *izq; /**< Hijo izquierdo. */
struct nodoAVL *padre; /**< Enlace al padre del nodo. */
} nodoAVL;
typedef nodoAVL* AVL;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 AVL.
* @param raiz Referencia a la raíz del árbol.
* @param x Valor a avl_insertar (no se insertan duplicados).
* @pre raiz apunta a una variable valida (o es NULL); su arbol inicial tiene enlaces finitos/aciclicos, orden estricto, padres consistentes y FE exactos de un AVL equilibrado.
* @note Retorna void: referencia raiz NULL, duplicado o fallo de malloc no producen estado de error retornado ni cambian el arbol. La API web rechaza duplicados antes de mutar; no equivale a ejecutar este cuerpo C.
* @note Un valor nuevo reserva exactamente un nodo, inicializa nro/FE/hijos/padre y luego lo publica mediante raiz o enlace del padre. Los campos de malloc no se leen antes de inicializarlos.
* @note Conserva identidades/valores de nodos previos; no libera reservas ni imprime. Recorre con padre/actual, propaga FE con n/padre y compone las rotaciones necesarias; enlaces y FE parciales no certifican un AVL terminado.
* @note Cada nueva reserva queda propiedad del llamador hasta liberarla con avl_liberarAVL. No modifica referencias prestadas externas; pueden cambiar los enlaces/raiz pero no la identidad de reservas previas.
*/
void avl_insertar(AVL *raiz, int x) {
if (raiz == NULL) {
return;
}
AVL padre = NULL, actual = *raiz;
while (actual != NULL) {
padre = actual;
if (x < actual->nro)
actual = actual->izq;
else if (x > actual->nro)
actual = actual->der;
else
return; // no duplicados
}
AVL nuevo = malloc(sizeof(*nuevo));
if (nuevo == NULL) {
return;
}
nuevo->nro = x;
nuevo->FE = 0;
nuevo->izq = nuevo->der = NULL;
nuevo->padre = padre;
if (padre == NULL) {
*raiz = nuevo;
return;
}
if (x < padre->nro)
padre->izq = nuevo;
else
padre->der = nuevo;
// Rebalanceo incremental tras inserción
AVL n = nuevo;
while (padre != NULL) {
if (n == padre->izq)
padre->FE--;
else
padre->FE++;
if (padre->FE == 0)
break;
if (padre->FE == -2) {
if (n->FE <= 0)
avl_RSD(raiz, padre);
else
avl_RDD(raiz, padre);
break;
}
if (padre->FE == 2) {
if (n->FE >= 0)
avl_RSI(raiz, padre);
else
avl_RDI(raiz, padre);
break;
}
n = padre;
padre = padre->padre;
}
}Eliminar · código C
Localiza el objetivo y aplica el caso de borrado correspondiente (hoja, un hijo, dos hijos o rebalanceo).
/**
* @brief Elimina el valor indicado del árbol AVL (con rebalanceo).
* @param raiz Referencia a la raíz del árbol.
* @param x Valor a avl_eliminar.
* @pre raiz es NULL o referencia una variable valida con un AVL finito/aciclico, orden estricto, padres consistentes y FE exactos.
* @note Retorna void. Referencia raiz NULL, vacio o valor ausente dejan el arbol sin cambios; la API web rechaza vacio/ausencia antes de mutar y no equivale a ejecutar este cuerpo C.
* @note Con dos hijos intercambia nro con el sucesor minimo del hijo derecho, conservando las reservas durante el intercambio. Despues libera la reserva del sucesor, no necesariamente la reserva encontrada inicialmente.
* @note Con cero/un hijo reenlaza raiz o padre y actualiza el padre del hijo antes de free. Libera exactamente una reserva si encuentra x; no reserva memoria ni imprime. Los alias a la reserva liberada dejan de ser utilizables; la reserva retenida puede cambiar de valor.
* @note Reequilibra desde el padre de la reserva retirada mediante alturas y rotaciones. Identidades vivas se conservan; los enlaces, orden y FE intermedios no certifican un AVL final. El llamador mantiene propiedad del arbol restante y debe liberarlo al terminar.
*/
void avl_eliminar(AVL *raiz, int x) {
if (raiz == NULL) {
return;
}
AVL z = avl_buscar(*raiz, x);
if (!z) return;
// Si tiene dos hijos, intercambiar con el sucesor inorden y descender
while (z->izq && z->der) {
AVL s = avl_minimo(z->der);
int tmp = z->nro;
z->nro = s->nro;
s->nro = tmp;
z = s; // continuar eliminando más abajo
}
// Ahora z tiene 0 o 1 hijo: avl_eliminar físicamente
AVL padre = z->padre;
AVL child = (z->izq) ? z->izq : z->der;
if (child) child->padre = padre;
if (!padre) {
*raiz = child;
} else if (padre->izq == z) {
padre->izq = child;
} else {
padre->der = child;
}
free(z);
// Reequilibrar subiendo desde el padre
if (padre) rebalancearTrasEliminar(raiz, padre);
}Buscar · código C
Navega por comparaciones hasta encontrar el valor o concluir que no existe.
/**
* @brief Busca un valor en el árbol AVL.
* @param raiz Raíz del árbol.
* @param x Valor a avl_buscar.
* @return Puntero al nodo con el valor o NULL si no se encuentra.
* @note Retorna un alias prestado a una reserva existente o NULL por ausencia/vacio. No reserva, libera ni modifica enlaces. El alias deja de ser utilizable cuando se libera esa reserva.
*/
AVL avl_buscar(AVL raiz, int x) {
if (!raiz)
return NULL;
if (x < raiz->nro)
return avl_buscar(raiz->izq, x);
if (x > raiz->nro)
return avl_buscar(raiz->der, x);
return raiz;
}Mínimo · código C
Avanza por la rama izquierda hasta el último nodo para obtener el menor valor del subárbol.
/**
* @brief Obtiene el nodo con el valor mínimo del subárbol dado.
* @param nodo Raíz del subárbol.
* @return Puntero al nodo con el valor mínimo.
* @pre nodo debe ser distinto de NULL.
* @note Requiere nodo no NULL y enlaces validos. Recorre izquierdo cambiando solo su alias local y retorna un alias prestado; no modifica la raiz, reserva ni libera memoria. El llamador debe comprobar el vacio.
*/
AVL avl_minimo(AVL nodo) {
while (nodo->izq)
nodo = nodo->izq;
return nodo;
}Máximo · código C
Avanza por la rama derecha hasta el último nodo para obtener el mayor valor del subárbol.
AVL avl_maximo(AVL raiz) {
AVL aux = raiz;
while (aux != NULL && aux->der != NULL) {
aux = aux->der;
}
return aux;
}Altura · código C
Calcula la altura estructural a partir de la profundidad máxima de sus ramas.
/**
* @brief Calcula la avl_altura del árbol (número de niveles).
* @param arbol Raíz del árbol.
* @return Altura del árbol (0 si está vacío).
* @note Cuenta niveles: vacio 0 y hoja 1. Calcula las alturas recursivamente sin consultar ni modificar FE o enlaces; no cuenta nodos.
*/
int avl_altura(AVL arbol) {
if (arbol == NULL)
return 0;
int altIzq = avl_altura(arbol->izq);
int altDer = avl_altura(arbol->der);
return (altIzq > altDer ? altIzq : altDer) + 1;
}Inorden · código C
Recorrido izquierda-raíz-derecha; en ABB produce valores ordenados de menor a mayor.
void avl_inorden(AVL nodo) {
if (nodo != NULL) {
avl_inorden(nodo->izq);
printf("%d ", nodo->nro);
avl_inorden(nodo->der);
}
}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 Comprueba equilibrio por alturas en cada subarbol.
* @param nodo Raiz prestada del subarbol; NULL es valido.
* @return 1 si todas las diferencias altura(der)-altura(izq) estan entre -1 y 1; 0 en otro caso.
* @pre Enlaces finitos, aciclicos y nodos vivos.
* @note No verifica orden ABB, padres ni el FE almacenado; la validacion del backend es distinta.
* @note No muta, reserva, libera ni imprime; cortocircuita al hallar desequilibrio.
* @note C no fija el orden de los operandos de la resta de alturas; ambas consultas son puras.
* @note Recalcula alturas por nodo: coste O(n*h), no certificado lineal.
*/
int avl_validar_fes(AVL nodo) {
if (nodo == NULL) {
return 1;
}
int fe = avl_altura(nodo->der) - avl_altura(nodo->izq);
if (fe < -1 || fe > 1) {
return 0;
}
if (!avl_validar_fes(nodo->izq)) {
return 0;
}
if (!avl_validar_fes(nodo->der)) {
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 AVL (postorden).
* @param raiz Raíz del árbol a liberar.
* @note Libera hijos izquierdo/derecho antes del padre. Recibe la raiz por valor y no pone a NULL la raiz del llamador: asignar NULL despues de esta llamada. Los alias a reservas liberadas dejan de ser utilizables; NULL no tiene efecto.
*/
void avl_liberarAVL(AVL raiz) {
if (!raiz)
return;
avl_liberarAVL(raiz->izq);
avl_liberarAVL(raiz->der);
free(raiz);
}