Sublista
Descripcion del TAD
Estructura jerarquica secuencial: cada nodo padre mantiene su propia sublista de hijos. En la animacion observa dos niveles de punteros (padres e hijos) y valida que cada operacion afecte solo la rama correspondiente sin corromper otras sublistas. La Sublista agrega un segundo nivel de enlaces: nodos padre y sus hijos. El foco didactico esta en aislar cambios por rama sin corromper otras relaciones.
Objetivo
Modificar una rama sin afectar a las demás.
Estrategia
Localizar primero el padre y luego recorrer sus hijos.
Invariante
Cada hijo pertenece a un único padre.
Memoria dinámica
La liberación de una rama no autoriza liberar ramas vecinas.
Errores frecuentes
- Insertar un hijo sin padre
- Compartir enlaces entre ramas
Glosario contextual
- Nodo
- Objeto dinámico con datos y uno o más enlaces.
- Enlace
- Campo puntero que conecta objetos.
- Alias
- Dos punteros que designan el mismo objeto.
- LIFO
- El último en entrar es el primero en salir.
- FIFO
- El primero en entrar es el primero en salir.
- Prioridad
- Criterio de selección independiente del orden físico.
- Circularidad
- El último enlace vuelve al inicio.
- malloc
- Reserva memoria; puede devolver NULL.
- free
- Libera una reserva que deja de ser válida.
Controles de ejecucion paso a paso
- Checkbox Interpretar codigo paso a paso: activado muestra toda la traza; desactivado aplica solo el resultado final.
- Botones de ejecucion: Reproducir y Reiniciar.
- Navegacion por traza: Anterior paso y Siguiente paso.
- Velocidad de simulacion: slider de -2x a +2x (0.00x = 1.00x real).
- En modo rapido (checkbox desactivado), el resultado visual final debe coincidir con el ultimo estado de la traza interpretada.
- Al llegar al ultimo paso, Siguiente paso se bloquea hasta cambiar entradas/operacion; Anterior paso se habilita solo cuando ya avanzaste.
Operaciones soportadas
- sublista_insertar_padre_final
- sublista_insertar_hijo_final
- sublista_eliminar_padre_primero
- sublista_eliminar_hijo_primero
- sublista_buscar_padre
- sublista_destruir
Operaciones pendientes / restricciones
- No existe eliminar_todos_los_hijos de un padre en el TAD suministrado.
Estructura del TAD en C
typedef struct Sublista {
int nro;
struct Sublista *sgte;
} Sublista;
typedef struct Nodo {
int nro;
struct Nodo *sgte;
Sublista *sub;
} Nodo;
Metodos del TAD en C
Codigo C: insertar_padre
Crea nodo padre en la lista principal de sublistas manteniendo su cadena independiente.
/**
* @brief Inserta un nuevo nodo padre al final de la lista principal.
* @param[in,out] lista Doble puntero a la lista principal.
* @param[in] valor_padre Valor del nuevo padre.
* @return Puntero al nuevo nodo insertado, o NULL si falla.
*/
Nodo *sublista_insertar_padre_final(Nodo **lista, int valor_padre) {
Nodo *nuevo;
Nodo *actual;
if (lista == NULL) {
return NULL;
}
nuevo = crear_padre(valor_padre);
if (nuevo == NULL) {
return NULL;
}
if (*lista == NULL) {
*lista = nuevo;
return nuevo;
}
actual = *lista;
while (actual->sgte != NULL) {
actual = actual->sgte;
}
actual->sgte = nuevo;
return nuevo;
}
Codigo C: insertar_hijo
Localiza el padre objetivo y agrega el hijo en su sublista, sin afectar otros padres.
/**
* @brief Inserta un nuevo nodo hijo al final de la sublista de un padre.
* @param[in,out] padre Puntero al nodo padre.
* @param[in] valor_hijo Valor del nuevo hijo.
* @return true si se insertó exitosamente, false en caso de error.
*/
bool sublista_insertar_hijo_final(Nodo *padre, int valor_hijo) {
Sublista *nuevo;
Sublista *actual;
if (padre == NULL) {
return false;
}
nuevo = crear_hijo(valor_hijo);
if (nuevo == NULL) {
return false;
}
if (padre->sub == NULL) {
padre->sub = nuevo;
return true;
}
actual = padre->sub;
while (actual->sgte != NULL) {
actual = actual->sgte;
}
actual->sgte = nuevo;
return true;
}
Codigo C: eliminar_padre
Elimina un padre y libera recursivamente/iterativamente su sublista de hijos asociada.
/**
* @brief Elimina la primera ocurrencia de un nodo padre y todos sus hijos.
* @param[in,out] lista Doble puntero a la lista.
* @param[in] valor_padre Valor del padre a eliminar.
* @return true si fue eliminado con éxito, false si no se encontró.
*/
bool sublista_eliminar_padre_primero(Nodo **lista, int valor_padre) {
Nodo *actual;
Nodo *anterior = NULL;
if (lista == NULL || *lista == NULL) {
return false;
}
actual = *lista;
while (actual != NULL) {
if (actual->nro == valor_padre) {
if (anterior == NULL) {
*lista = actual->sgte;
} else {
anterior->sgte = actual->sgte;
}
destruir_hijos(&actual->sub);
free(actual);
return true;
}
anterior = actual;
actual = actual->sgte;
}
return false;
}
Codigo C: eliminar_hijo
Dentro del padre indicado, busca el hijo por valor y lo elimina ajustando enlaces locales.
/**
* @brief Elimina la primera ocurrencia de un hijo en la sublista de un padre.
* @param[in,out] padre Puntero al nodo padre.
* @param[in] valor_hijo Valor del hijo a eliminar.
* @return true si se eliminó correctamente, false si no se encontró.
*/
bool sublista_eliminar_hijo_primero(Nodo *padre, int valor_hijo) {
Sublista *actual;
Sublista *anterior = NULL;
if (padre == NULL || padre->sub == NULL) {
return false;
}
actual = padre->sub;
while (actual != NULL) {
if (actual->nro == valor_hijo) {
if (anterior == NULL) {
padre->sub = actual->sgte;
} else {
anterior->sgte = actual->sgte;
}
free(actual);
return true;
}
anterior = actual;
actual = actual->sgte;
}
return false;
}
Codigo C: hijos_de
Devuelve la coleccion de hijos del padre solicitado sin modificar la estructura.
/* Consulta de hijos en C: buscar padre y copiar su sublista a un arreglo. */
Nodo *padre = sublista_buscar_padre(lista, valor_padre);
if (padre != NULL) {
int hijos[256];
int usados = sublista_copiar_hijos(padre, hijos, 256);
/* hijos[0..usados-1] contiene los valores de la sublista */
}
Codigo C: limpiar
Recorre la estructura liberando todos los nodos y deja el puntero raiz en estado nulo para reinicio seguro.
/**
* @brief Libera completamente la memoria de todos los padres y sus respectivos hijos.
* @param[in,out] lista Doble puntero a la lista principal.
*/
void sublista_destruir(Nodo **lista) {
Nodo *actual;
Nodo *next;
if (lista == NULL) {
return;
}
actual = *lista;
while (actual != NULL) {
next = actual->sgte;
destruir_hijos(&actual->sub);
free(actual);
actual = next;
}
*lista = NULL;
}
/* Reinicio recomendado del TAD luego de liberar memoria */
/**
* @brief Inicializa la lista principal de nodos padre estableciéndola en NULL.
* @param[out] lista Doble puntero a la lista a inicializar.
*/
void sublista_inicializar(Nodo **lista) {
if (lista == NULL) {
return;
}
*lista = NULL;
}