Métodos de Ordenamiento
¿Qué representa este TAD?
Ordenar un arreglo consiste en reorganizar sus valores de menor a mayor. Los algoritmos llegan al mismo objetivo con distintas comparaciones, movimientos y memoria auxiliar.
Prueba este ejemplo
Crea 4, 1, 3, 2 y elige Burbuja. Al terminar debe quedar 1, 2, 3, 4. Para comparar con Inserción, vuelve a crear la misma entrada inicial.
Qué observar · tres pasos
- Predice si la siguiente comparación requiere intercambiar valores.
- Observa los índices activos y distingue comparación de escritura.
- Comprueba el arreglo final y compara métodos usando los mismos datos iniciales.
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.
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
Fichas por algoritmo: elige uno para profundizar
Empieza con Burbuja o Inserción y el ejemplo anterior. Abre una ficha cada vez: no necesitas estudiar los once métodos a la vez.
Intercambio directo
Prueba y predice
Entrada: 3, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Qué ocurre al comparar 3 con 1?
Contrastar mi predicción
Se intercambian: queda [1, 3, 2]. Después se compara el 1 con el 2; esa comparación no exige intercambio.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Compara cada par (i, j) y permuta cuando encuentra desorden.
Qué observar
- predice cada intercambio
- explica el prefijo confirmado
Error que evitar
No confundas cada comparación con un intercambio: sólo se permutan valores cuando están en el orden incorrecto.
Costo y memoria
- Mejor caso: O(n²).
- Caso promedio: O(n²).
- Peor caso: O(n²).
- Memoria: O(1).
Selección directa
Prueba y predice
Entrada: 3, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿El primer mínimo encontrado se coloca inmediatamente?
Contrastar mi predicción
No. Se termina de buscar el menor en el tramo pendiente. El 1 queda en la primera posición al cerrar esa búsqueda.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Busca el mínimo del tramo no ordenado y lo coloca en la posición actual.
Qué observar
- identifica el mínimo provisional
- justifica el prefijo ordenado
Error que evitar
No creas que el mínimo encontrado se coloca al comparar: primero se busca en todo el tramo pendiente y luego se ubica.
Costo y memoria
- Mejor caso: O(n²).
- Caso promedio: O(n²).
- Peor caso: O(n²).
- Memoria: O(1).
Inserción directa
Prueba y predice
Entrada: 3, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Dónde se guarda el 1 mientras el 3 se desplaza?
Contrastar mi predicción
En la clave temporal. Se mueve el 3 a la derecha y después se escribe el 1 en el hueco.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Inserta cada elemento en su lugar desplazando mayores hacia la derecha.
Qué observar
- ubica el hueco
- explica la estabilidad
Error que evitar
No pierdas el valor de la clave mientras se desplazan otros datos: su copia temporal permite insertarla al final del desplazamiento.
Costo y memoria
- Mejor caso: O(n).
- Caso promedio: O(n²).
- Peor caso: O(n²).
- Memoria: O(1).
Burbuja mejorada
Prueba y predice
Entrada: 3, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Qué valor llegará al final tras la primera pasada?
Contrastar mi predicción
El 3: primero se compara con 1 y después con 2. Queda [1, 2, 3]; la siguiente pasada confirma que no hace falta intercambiar.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Compara adyacentes y burbujea los mayores hacia el final en cada pasada.
Qué observar
- predice la frontera de pasada
- explica la terminación temprana
Error que evitar
No supongas que una pasada ordena todo: observa qué extremo queda resuelto y cuándo una pasada sin intercambios permite terminar.
Costo y memoria
- Mejor caso: O(n).
- Caso promedio: O(n²).
- Peor caso: O(n²).
- Memoria: O(1).
Shell sort
Prueba y predice
Entrada: 4, 3, 2, 1. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
Con intervalo 2, ¿qué posiciones forman el primer grupo?
Contrastar mi predicción
Las posiciones 0 y 2: valores 4 y 2. El otro grupo usa las posiciones 1 y 3, con valores 3 y 1. Cuando el intervalo baja a 1 se ordena como una inserción.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Generaliza inserción usando saltos (gaps) decrecientes hasta 1.
Qué observar
- forma los grupos por intervalo
- explica el paso final con intervalo uno
Error que evitar
No interpretes cada salto como vecinos consecutivos: los grupos se forman con la separación actual, que luego disminuye.
Costo y memoria
- Mejor caso: depende de gaps.
- Caso promedio: depende de gaps.
- Peor caso: O(n²).
- Memoria: O(1).
Quick sort
Prueba y predice
Entrada: 3, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Cuál es el pivote inicial de esta implementación?
Contrastar mi predicción
Se copia el valor central, 1. Los índices avanzan desde los extremos y particionan alrededor de ese valor; el pivote copiado no cambia porque se mueva una celda.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Particiona por pivote y ordena recursivamente subarreglos.
Qué observar
- sigue i y j
- reconstruye el árbol de llamadas
Error que evitar
No sigas sólo la posición inicial del pivote: el algoritmo conserva un valor de referencia mientras los elementos se intercambian.
Costo y memoria
- Mejor caso: O(n log n).
- Caso promedio: O(n log n).
- Peor caso: O(n²).
- Memoria: O(log n) promedio; O(n) peor.
Merge sort
Prueba y predice
Entrada: 3, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Basta con ordenar las mitades para terminar?
Contrastar mi predicción
No. Tras dividir, se fusionan los segmentos ordenados. Al fusionar [1, 3] y [2], el auxiliar recibe 1, luego 2 y luego 3.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Divide recursivamente y fusiona subarreglos ordenados usando auxiliar.
Qué observar
- reconstruye divisiones
- explica una fusión estable
Error que evitar
No confundas ordenar cada mitad con terminar: todavía hay que fusionar las mitades en orden usando el auxiliar.
Costo y memoria
- Mejor caso: O(n log n).
- Caso promedio: O(n log n).
- Peor caso: O(n log n).
- Memoria: O(n).
Heap sort
Prueba y predice
Entrada: 3, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Qué valor se coloca al final al extraer la primera raíz?
Contrastar mi predicción
El 3, máximo del montículo. La zona pendiente reduce su tamaño y recupera la relación padre mayor o igual que sus hijos.
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Construye max-heap y extrae repetidamente la raíz al final del arreglo.
Qué observar
- verifica la propiedad de heap
- distingue heap y sufijo ordenado
Error que evitar
No confundas un heap con un arreglo totalmente ordenado: la propiedad padre-hijos permite elegir extremos, no ordena todos los pares.
Costo y memoria
- Mejor caso: O(n log n).
- Caso promedio: O(n log n).
- Peor caso: O(n log n).
- Memoria: O(log n), pila de heapify recursivo.
Counting sort
Prueba y predice
Entrada: 2, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Cuántas veces debe escribirse el 2 al reconstruir?
Contrastar mi predicción
Dos. Las frecuencias son 1 para el valor 1 y 2 para el valor 2. El arreglo reconstruido es [1, 2, 2].
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Cuenta ocurrencias por rango de valores y reconstruye el arreglo.
Qué observar
- calcula una urna
- explica el coste dependiente del rango
Error que evitar
No confundas cantidad de datos n con rango k: pocos valores muy separados pueden superar el límite del rango.
Costo y memoria
- Mejor caso: O(n+k).
- Caso promedio: O(n+k).
- Peor caso: O(n+k).
- Memoria: O(k).
Binsort
Prueba y predice
Entrada: 2, 1, 2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿Verás un algoritmo independiente con listas de urnas?
Contrastar mi predicción
No en este TAD. Binsort llama a Counting: cuenta una aparición de 1 y dos de 2, y reconstruye [1, 2, 2].
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
En este TAD delega en counting sort.
Qué observar
- explica la delegación
- reconstruye desde urnas
Error que evitar
No esperes urnas independientes en este TAD: Binsort delega en Counting y hereda su límite de rango.
Costo y memoria
- Mejor caso: O(n+k).
- Caso promedio: O(n+k).
- Peor caso: O(n+k).
- Memoria: O(k).
Radix sort
Prueba y predice
Entrada: -12, 3, -2. Selecciona este método, activa Paso a paso y pulsa Preparar recorrido.
¿En qué orden deben recomponerse las magnitudes negativas 2 y 12?
Contrastar mi predicción
De mayor a menor magnitud: primero -12 y después -2. Se agrega el grupo no negativo y queda [-12, -2, 3].
Avanza con Siguiente paso y busca el cambio en el gráfico. Los primeros pasos pueden validar la entrada o declarar variables sin mover valores.
Qué hace
Ordena por dígitos (LSD) y maneja negativos separando grupos.
Qué observar
- identifica el dígito activo
- explica el tratamiento de negativos
Error que evitar
No trates un número negativo como si sus dígitos bastaran para colocarlo: sigue la separación de signos y la recomposición del orden.
Costo y memoria
- Mejor caso: O(d(n+b)).
- Caso promedio: O(d(n+b)).
- Peor caso: O(d(n+b)).
- Memoria: O(n+b).
Glosario contextual y cómo leer la complejidad
La complejidad explica cómo aumenta el trabajo con la entrada, no la velocidad elegida para la animación. n es cantidad de valores; k, amplitud del rango; d, cantidad de dígitos; b, base usada para los dígitos.
- Pivote
- Valor copiado que guía una partición de Quicksort.
- Estabilidad
- Conservar el orden relativo de elementos con claves iguales.
- In-place
- Trabajar sin memoria auxiliar proporcional a la entrada.
- Heap
- Árbol completo representado en arreglo con una regla entre cada padre y sus hijos.
- Bucket o urna
- Grupo asociado a un valor o dígito durante una distribución.
Atajos de teclado
- Alt + →: avanzar al siguiente paso.
- Alt + ←: regresar al paso anterior.
- Alt + Inicio: volver al comienzo de la traza.
- Alt + Fin: ir al último paso.
- Alt + P: pausar la reproducción.
- Alt + R: reproducir la traza; si está al final, comienza otra vez.
Elige un ejemplo pequeño para empezar
La interfaz admite de 1 a 80 enteros. Counting y Binsort requieren un rango inclusivo máximo−mínimo+1 no mayor que 1.000.000. Si el ejemplo no se acepta, corrige el dato indicado antes de volver a ejecutar.
Referencia de operaciones y datos de entrada
Operaciones de la aplicación y datos
- Crear arreglo
create_array - Valores (csv) (texto)
- Generar arreglo aleatorio
generate_random_array - Tamaño (entero); Mínimo (entero); Máximo (entero)
- Reiniciar
reset - Sin datos adicionales.
- Ejecutar ordenamiento
run - Modo (texto)
- Seleccionar algoritmo
select_algorithm - Algoritmo (texto)
- Paso de ejecución
step - Dirección (texto); Cursor (entero)
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.
La interfaz admite entre 1 y 80 enteros int32, separados por comas. El catálogo ofrece once algoritmos. Counting y Binsort admiten rango inclusivo máximo−mínimo+1 hasta 1000000; las entradas grandes conservan eventos completos mediante representación dispersa y páginas. Radix separa negativos y no negativos. Las funciones imprimir/copiar/probar del C son utilidades, no algoritmos adicionales del selector.
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.
Código fuente completo del TAD
Descarga el archivo C principal de Métodos de ordenamiento y su encabezado para estudiarlo o compilarlo en tu equipo.
Referencia: estructura del TAD en C
#define ORDENAMIENTO_OK 1 #define ORDENAMIENTO_ERROR 0 void imprimir_arreglo(const int arreglo[], size_t n); /** * @brief Copia los elementos de un arreglo origen hacia un arreglo destino. * * @param destino Arreglo destino. * @param origen Arreglo origen. * @param n Número de elementos a copiar. * @return ORDENAMIENTO_OK si la copia fue correcta; ORDENAMIENTO_ERROR en caso contrario. * @pre Buffers vivos de al menos n ints, destino escribible y origen legible, sin solapamiento; n*sizeof(int) representable en size_t. * @note NULL buffers o n==0 retorna ORDENAMIENTO_ERROR sin copiar. Usa memcpy, no memmove; no admite buffers solapados ni valida longitud. No reserva/libera. */ int copiar_arreglo(int destino[], const int origen[], size_t n); /** * @brief Ordena un arreglo usando el método de intercambio directo. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @note Tiempo O(n^2), memoria O(1); no estable por intercambios no adyacentes. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ void ordenar_intercambio(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando selección directa. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @note Tiempo O(n^2), memoria O(1); no estable por intercambio con el minimo distante. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ void ordenar_seleccion(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando inserción directa. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @note Mejor O(n), peor O(n^2), memoria O(1); estable por desplazar solo valores estrictamente mayores. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ void ordenar_insercion(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando burbuja mejorada. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @note Mejor O(n), peor O(n^2), memoria O(1); estable por intercambiar vecinos solo si son estrictamente mayores. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ void ordenar_burbuja(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando Shell Sort. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @note Gaps n/2, n/4, ...; peor O(n^2), memoria O(1); no estable. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ void ordenar_shell(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando QuickSort. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @note Promedio O(n log n), peor O(n^2); pila O(log n) promedio, O(n) peor; no estable. n debe permitir indices int y suma de extremos int. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ void ordenar_quicksort(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando MergeSort. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0 o fallo de memoria. * @note Tiempo O(n log n), auxiliar O(n), pila O(log n); estable porque la mezcla toma primero el lado izquierdo en igualdad. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ int ordenar_mergesort(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando HeapSort. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @note Tiempo O(n log n), sin arreglo auxiliar; heapify recursivo usa pila O(log n), no espacio total O(1); no estable. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ void ordenar_heapsort(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando Counting Sort. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0, rango mayor que ORDENAMIENTO_RANGO_MAX, tamaño no representable o fallo de memoria. * @note Tiempo O(n+k), memoria O(k), k=max-min+1 <= ORDENAMIENTO_RANGO_MAX; reconstruye enteros por frecuencia, sin preservar identidad de registros iguales. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ int ordenar_counting_sort(int arreglo[], size_t n); /** * @brief Ordena delegando en Counting Sort; conserva sus límites de rango y códigos de error. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0, rango mayor que ORDENAMIENTO_RANGO_MAX, tamaño no representable o fallo de memoria. * @note Delegacion exacta a Counting Sort: O(n+k) tiempo, O(k) memoria y mismo limite; no es una implementacion independiente de buckets. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ int ordenar_binsort(int arreglo[], size_t n); /** * @brief Ordena un arreglo usando Radix Sort LSD en base 10. * * Esta implementación acepta enteros negativos separándolos de los no negativos, * ordenando magnitudes y recombinando al final. * * @param arreglo Arreglo de enteros a ordenar. * @param n Número de elementos del arreglo. * @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0 o fallo de memoria. * @note Base 10, O(d(n+10)) tiempo y O(n+10) memoria. Conteo por digito estable; la inversion final del grupo negativo no garantiza estabilidad de registros negativos iguales. INT_MIN usa magnitud uint32_t y recomposicion protegida. * @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado. */ int ordenar_radixsort(int arreglo[], size_t n); /** * @brief Ejecuta y muestra un algoritmo de ordenamiento sobre una copia del arreglo base. * * @param nombre Nombre descriptivo del algoritmo. * @param ordenar Función de ordenamiento que no retorna estado. * @param base Arreglo base. * @param n Número de elementos. * @pre nombre es cadena viva terminada en NUL; base contiene n ints legibles, n*sizeof(int) representable. Callback valido recibe copia prestada, no la libera ni retiene; se cumplen sus limites particulares. * @note NULL nombre/callback/base o n==0 no hace nada. Malloc fallido imprime error. Copia base, ejecuta callback, imprime copia y la libera; base queda intacta bajo precondiciones. */ void probar_algoritmo_void(const char *nombre, void (*ordenar)(int[], size_t), const int base[], size_t n); /** * @brief Ejecuta y muestra un algoritmo de ordenamiento que retorna estado. * * @param nombre Nombre descriptivo del algoritmo. * @param ordenar Función de ordenamiento que retorna ORDENAMIENTO_OK o ORDENAMIENTO_ERROR. * @param base Arreglo base. * @param n Número de elementos. * @pre nombre es cadena viva terminada en NUL; base contiene n ints legibles, n*sizeof(int) representable. Callback valido recibe copia prestada, no la libera ni retiene; se cumplen sus limites particulares. * @note NULL nombre/callback/base o n==0 no hace nada. Error de malloc imprime diagnostico; callback con retorno cero imprime error y libera copia sin imprimir arreglo. Exito no cero imprime copia y la libera. */ void probar_algoritmo_int(const char *nombre, int (*ordenar)(int[], size_t), const int base[], size_t n);
Código C y llamadores equivalentes
Intercambio · código C
Compara pares (i,j) y permuta cuando detecta desorden en el arreglo.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Intercambia el contenido de dos variables enteras.
*
* @param a Puntero al primer entero.
* @param b Puntero al segundo entero.
* @note NULL a o b se ignora. Con ambos validos son ints escribibles; mismo entero permitido sin cambio. No reserva/libera.
*/
static void intercambiar(int *a, int *b) {
int temporal;
if (a == NULL || b == NULL) return;
temporal = *a;
*a = *b;
*b = temporal;
}
/**
* @brief Ordena un arreglo usando el método de intercambio directo.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @note Tiempo O(n^2), memoria O(1); no estable por intercambios no adyacentes.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
void ordenar_intercambio(int arreglo[], size_t n) {
size_t i, j;
if (!arreglo_valido(arreglo, n)) return;
for (i = 0; i + 1 < n; ++i)
for (j = i + 1; j < n; ++j)
if (arreglo[i] > arreglo[j]) intercambiar(&arreglo[i], &arreglo[j]);
}Selección · código C
Busca el mínimo del tramo no ordenado y lo ubica en la posición actual.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Intercambia el contenido de dos variables enteras.
*
* @param a Puntero al primer entero.
* @param b Puntero al segundo entero.
* @note NULL a o b se ignora. Con ambos validos son ints escribibles; mismo entero permitido sin cambio. No reserva/libera.
*/
static void intercambiar(int *a, int *b) {
int temporal;
if (a == NULL || b == NULL) return;
temporal = *a;
*a = *b;
*b = temporal;
}
/**
* @brief Ordena un arreglo usando selección directa.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @note Tiempo O(n^2), memoria O(1); no estable por intercambio con el minimo distante.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
void ordenar_seleccion(int arreglo[], size_t n) {
size_t i, j, indice_menor;
if (!arreglo_valido(arreglo, n)) return;
for (i = 0; i + 1 < n; ++i) {
indice_menor = i;
for (j = i + 1; j < n; ++j)
if (arreglo[j] < arreglo[indice_menor]) indice_menor = j;
if (indice_menor != i) intercambiar(&arreglo[i], &arreglo[indice_menor]);
}
}Inserción · código C
Inserta cada clave en su posición desplazando elementos mayores a la derecha.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Ordena un arreglo usando inserción directa.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @note Mejor O(n), peor O(n^2), memoria O(1); estable por desplazar solo valores estrictamente mayores.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
void ordenar_insercion(int arreglo[], size_t n) {
size_t i;
if (!arreglo_valido(arreglo, n)) return;
for (i = 1; i < n; ++i) {
int clave = arreglo[i];
size_t j = i;
while (j > 0 && arreglo[j - 1] > clave) {
arreglo[j] = arreglo[j - 1];
--j;
}
arreglo[j] = clave;
}
}Burbuja · código C
Compara adyacentes y mueve los mayores al final en cada pasada.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Intercambia el contenido de dos variables enteras.
*
* @param a Puntero al primer entero.
* @param b Puntero al segundo entero.
* @note NULL a o b se ignora. Con ambos validos son ints escribibles; mismo entero permitido sin cambio. No reserva/libera.
*/
static void intercambiar(int *a, int *b) {
int temporal;
if (a == NULL || b == NULL) return;
temporal = *a;
*a = *b;
*b = temporal;
}
/**
* @brief Ordena un arreglo usando burbuja mejorada.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @note Mejor O(n), peor O(n^2), memoria O(1); estable por intercambiar vecinos solo si son estrictamente mayores.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
void ordenar_burbuja(int arreglo[], size_t n) {
size_t pasada, j;
int hubo_intercambio;
if (!arreglo_valido(arreglo, n)) return;
for (pasada = 0; pasada + 1 < n; ++pasada) {
hubo_intercambio = 0;
for (j = 0; j + 1 < n - pasada; ++j) {
if (arreglo[j] > arreglo[j + 1]) {
intercambiar(&arreglo[j], &arreglo[j + 1]);
hubo_intercambio = 1;
}
}
if (!hubo_intercambio) break;
}
}Shell · código C
Aplica inserción con gaps decrecientes hasta converger en gap=1.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Ordena un arreglo usando Shell Sort.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @note Gaps n/2, n/4, ...; peor O(n^2), memoria O(1); no estable.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
void ordenar_shell(int arreglo[], size_t n) {
size_t intervalo;
if (!arreglo_valido(arreglo, n)) return;
for (intervalo = n / 2; intervalo > 0; intervalo /= 2) {
size_t i;
for (i = intervalo; i < n; ++i) {
int temporal = arreglo[i];
size_t j = i;
while (j >= intervalo && arreglo[j - intervalo] > temporal) {
arreglo[j] = arreglo[j - intervalo];
j -= intervalo;
}
arreglo[j] = temporal;
}
}
}Quicksort · código C
Particiona por pivote central y ordena recursivamente subrangos.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Intercambia el contenido de dos variables enteras.
*
* @param a Puntero al primer entero.
* @param b Puntero al segundo entero.
* @note NULL a o b se ignora. Con ambos validos son ints escribibles; mismo entero permitido sin cambio. No reserva/libera.
*/
static void intercambiar(int *a, int *b) {
int temporal;
if (a == NULL || b == NULL) return;
temporal = *a;
*a = *b;
*b = temporal;
}
/**
* @brief Particiona un arreglo para QuickSort usando pivote central (función auxiliar).
*
* @param arreglo Arreglo de enteros.
* @param primero Índice inicial.
* @param ultimo Índice final.
* @pre Arreglo escribible; 0 <= primero <= ultimo dentro del buffer. primero+ultimo y ultimo+1 deben caber en int en todos los frames.
* @note Sin guardas NULL/rango; pivote central, particion con intercambios, recursion sobre segmentos. No reserva/libera ni garantiza profundidad arbitraria.
*/
static void quicksort_recursivo(int arreglo[], int primero, int ultimo) {
int i = primero, j = ultimo, pivote = arreglo[(primero + ultimo) / 2];
while (i <= j) {
while (arreglo[i] < pivote) ++i;
while (arreglo[j] > pivote) --j;
if (i <= j) {
intercambiar(&arreglo[i], &arreglo[j]);
++i; --j;
}
}
if (primero < j) quicksort_recursivo(arreglo, primero, j);
if (i < ultimo) quicksort_recursivo(arreglo, i, ultimo);
}
/**
* @brief Ordena un arreglo usando QuickSort.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @note Promedio O(n log n), peor O(n^2); pila O(log n) promedio, O(n) peor; no estable. n debe permitir indices int y suma de extremos int.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
void ordenar_quicksort(int arreglo[], size_t n) {
if (!arreglo_valido(arreglo, n)) return;
quicksort_recursivo(arreglo, 0, (int)n - 1);
}Mergesort · código C
Divide recursivamente y fusiona subarreglos con un auxiliar.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Mezcla dos subarreglos ordenados dentro del arreglo principal (función auxiliar para MergeSort).
*
* @param arreglo Arreglo de enteros.
* @param auxiliar Arreglo auxiliar.
* @param izquierda Índice inicial.
* @param medio Índice medio.
* @param derecha Índice final.
* @pre 0 <= izquierda <= medio < derecha dentro de ambos buffers; derecha+1 cabe en size_t; mitades ya ordenadas. Buffers escribibles y disjuntos.
* @note Escribe auxiliar en el mismo rango y lo copia de vuelta; usa <= para conservar izquierda en empate. No reserva/libera ni valida NULL/rangos.
*/
static void mezclar(int arreglo[], int auxiliar[], size_t izquierda, size_t medio, size_t derecha) {
size_t i = izquierda, j = medio + 1, k = izquierda;
while (i <= medio && j <= derecha) {
if (arreglo[i] <= arreglo[j]) auxiliar[k++] = arreglo[i++];
else auxiliar[k++] = arreglo[j++];
}
while (i <= medio) auxiliar[k++] = arreglo[i++];
while (j <= derecha) auxiliar[k++] = arreglo[j++];
for (i = izquierda; i <= derecha; ++i) arreglo[i] = auxiliar[i];
}
/**
* @brief Función recursiva auxiliar de MergeSort.
*
* @param arreglo Arreglo de enteros.
* @param auxiliar Arreglo auxiliar.
* @param izquierda Índice inicial.
* @param derecha Índice final.
* @pre Buffers escribibles disjuntos con rango valido y derecha+1 representable en size_t.
* @note izquierda >= derecha retorna sin escritura. Caller provee auxiliar; divide con izquierda+(derecha-izquierda)/2. No reserva/libera ni valida punteros.
*/
static void mergesort_recursivo(int arreglo[], int auxiliar[], size_t izquierda, size_t derecha) {
if (izquierda >= derecha) return;
size_t medio = izquierda + (derecha - izquierda) / 2;
mergesort_recursivo(arreglo, auxiliar, izquierda, medio);
mergesort_recursivo(arreglo, auxiliar, medio + 1, derecha);
mezclar(arreglo, auxiliar, izquierda, medio, derecha);
}
/**
* @brief Ordena un arreglo usando MergeSort.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0 o fallo de memoria.
* @note Tiempo O(n log n), auxiliar O(n), pila O(log n); estable porque la mezcla toma primero el lado izquierdo en igualdad.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
int ordenar_mergesort(int arreglo[], size_t n) {
int *auxiliar;
if (!arreglo_valido(arreglo, n)) return ORDENAMIENTO_ERROR;
auxiliar = (int *)malloc(n * sizeof(int));
if (auxiliar == NULL) return ORDENAMIENTO_ERROR;
mergesort_recursivo(arreglo, auxiliar, 0, n - 1);
free(auxiliar);
return ORDENAMIENTO_OK;
}Heapsort · código C
Construye max-heap y extrae la raíz para ordenar in-place.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Intercambia el contenido de dos variables enteras.
*
* @param a Puntero al primer entero.
* @param b Puntero al segundo entero.
* @note NULL a o b se ignora. Con ambos validos son ints escribibles; mismo entero permitido sin cambio. No reserva/libera.
*/
static void intercambiar(int *a, int *b) {
int temporal;
if (a == NULL || b == NULL) return;
temporal = *a;
*a = *b;
*b = temporal;
}
/**
* @brief Restaura la propiedad de montículo máximo desde un índice dado (función auxiliar para HeapSort).
*
* @param arreglo Arreglo de enteros.
* @param n Tamaño lógico del montículo.
* @param raiz Índice de la raíz del submontículo.
* @pre Arreglo escribible con n entradas; raiz < n y cada 2*raiz+2 visitado representable en size_t. Hijos son heaps maximos.
* @note No guardas NULL/limites; compara izquierdo antes de derecho con mejora estricta. No reserva/libera, recursion sobre hijo seleccionado. No soporte certificado para indices enormes.
*/
static void heapify(int arreglo[], size_t n, size_t raiz) {
size_t mayor = raiz, izquierdo = 2 * raiz + 1, derecho = 2 * raiz + 2;
if (izquierdo < n && arreglo[izquierdo] > arreglo[mayor]) mayor = izquierdo;
if (derecho < n && arreglo[derecho] > arreglo[mayor]) mayor = derecho;
if (mayor != raiz) {
intercambiar(&arreglo[raiz], &arreglo[mayor]);
heapify(arreglo, n, mayor);
}
}
/**
* @brief Ordena un arreglo usando HeapSort.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @note Tiempo O(n log n), sin arreglo auxiliar; heapify recursivo usa pila O(log n), no espacio total O(1); no estable.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
void ordenar_heapsort(int arreglo[], size_t n) {
size_t i;
if (!arreglo_valido(arreglo, n)) return;
for (i = n / 2; i > 0; --i) heapify(arreglo, n, i - 1);
for (i = n; i > 1; --i) {
intercambiar(&arreglo[0], &arreglo[i - 1]);
heapify(arreglo, i - 1, 0);
}
}Counting Sort · código C
Cuenta ocurrencias por valor y reconstruye el arreglo ordenado.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Obtiene el menor y mayor valor de un arreglo (función auxiliar).
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos.
* @param minimo Dirección donde se almacena el mínimo.
* @param maximo Dirección donde se almacena el máximo.
* @return ORDENAMIENTO_OK si se calcularon los valores; ORDENAMIENTO_ERROR en caso contrario.
* @pre Con n>0 arreglo legible de n ints; minimo/maximo externos escribibles, disjuntos entre si y de arreglo.
* @note NULL arreglo/salidas o n==0 retorna ORDENAMIENTO_ERROR sin escribir. Exito escribe ambos y retorna ORDENAMIENTO_OK; no reserva/libera ni modifica arreglo bajo precondiciones.
*/
static int obtener_minimo_maximo(const int arreglo[], size_t n, int *minimo, int *maximo) {
size_t i;
if (!arreglo_valido(arreglo, n) || minimo == NULL || maximo == NULL) return ORDENAMIENTO_ERROR;
*minimo = arreglo[0]; *maximo = arreglo[0];
for (i = 1; i < n; ++i) {
if (arreglo[i] < *minimo) *minimo = arreglo[i];
if (arreglo[i] > *maximo) *maximo = arreglo[i];
}
return ORDENAMIENTO_OK;
}
/**
* @brief Ordena un arreglo usando Counting Sort.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0, rango mayor que ORDENAMIENTO_RANGO_MAX, tamaño no representable o fallo de memoria.
* @note Tiempo O(n+k), memoria O(k), k=max-min+1 <= ORDENAMIENTO_RANGO_MAX; reconstruye enteros por frecuencia, sin preservar identidad de registros iguales.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
int ordenar_counting_sort(int arreglo[], size_t n) {
int minimo, maximo; size_t rango, i, indice; int *conteo;
if (!arreglo_valido(arreglo, n)) return ORDENAMIENTO_ERROR;
if (!obtener_minimo_maximo(arreglo, n, &minimo, &maximo)) return ORDENAMIENTO_ERROR;
rango = (size_t)((long long)maximo - (long long)minimo + 1LL);
if (rango > ORDENAMIENTO_RANGO_MAX || rango > SIZE_MAX / sizeof(int)) return ORDENAMIENTO_ERROR;
conteo = (int *)calloc(rango, sizeof(int));
if (conteo == NULL) return ORDENAMIENTO_ERROR;
for (i = 0; i < n; ++i) ++conteo[arreglo[i] - minimo];
indice = 0;
for (i = 0; i < rango; ++i)
while (conteo[i] > 0) { arreglo[indice++] = (int)i + minimo; --conteo[i]; }
free(conteo);
return ORDENAMIENTO_OK;
}Binsort · código C
Delega en counting sort según implementación del TAD C.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Obtiene el menor y mayor valor de un arreglo (función auxiliar).
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos.
* @param minimo Dirección donde se almacena el mínimo.
* @param maximo Dirección donde se almacena el máximo.
* @return ORDENAMIENTO_OK si se calcularon los valores; ORDENAMIENTO_ERROR en caso contrario.
* @pre Con n>0 arreglo legible de n ints; minimo/maximo externos escribibles, disjuntos entre si y de arreglo.
* @note NULL arreglo/salidas o n==0 retorna ORDENAMIENTO_ERROR sin escribir. Exito escribe ambos y retorna ORDENAMIENTO_OK; no reserva/libera ni modifica arreglo bajo precondiciones.
*/
static int obtener_minimo_maximo(const int arreglo[], size_t n, int *minimo, int *maximo) {
size_t i;
if (!arreglo_valido(arreglo, n) || minimo == NULL || maximo == NULL) return ORDENAMIENTO_ERROR;
*minimo = arreglo[0]; *maximo = arreglo[0];
for (i = 1; i < n; ++i) {
if (arreglo[i] < *minimo) *minimo = arreglo[i];
if (arreglo[i] > *maximo) *maximo = arreglo[i];
}
return ORDENAMIENTO_OK;
}
/**
* @brief Ordena un arreglo usando Counting Sort.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0, rango mayor que ORDENAMIENTO_RANGO_MAX, tamaño no representable o fallo de memoria.
* @note Tiempo O(n+k), memoria O(k), k=max-min+1 <= ORDENAMIENTO_RANGO_MAX; reconstruye enteros por frecuencia, sin preservar identidad de registros iguales.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
int ordenar_counting_sort(int arreglo[], size_t n) {
int minimo, maximo; size_t rango, i, indice; int *conteo;
if (!arreglo_valido(arreglo, n)) return ORDENAMIENTO_ERROR;
if (!obtener_minimo_maximo(arreglo, n, &minimo, &maximo)) return ORDENAMIENTO_ERROR;
rango = (size_t)((long long)maximo - (long long)minimo + 1LL);
if (rango > ORDENAMIENTO_RANGO_MAX || rango > SIZE_MAX / sizeof(int)) return ORDENAMIENTO_ERROR;
conteo = (int *)calloc(rango, sizeof(int));
if (conteo == NULL) return ORDENAMIENTO_ERROR;
for (i = 0; i < n; ++i) ++conteo[arreglo[i] - minimo];
indice = 0;
for (i = 0; i < rango; ++i)
while (conteo[i] > 0) { arreglo[indice++] = (int)i + minimo; --conteo[i]; }
free(conteo);
return ORDENAMIENTO_OK;
}
/**
* @brief Ordena delegando en Counting Sort; conserva sus límites de rango y códigos de error.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0, rango mayor que ORDENAMIENTO_RANGO_MAX, tamaño no representable o fallo de memoria.
* @note Delegacion exacta a Counting Sort: O(n+k) tiempo, O(k) memoria y mismo limite; no es una implementacion independiente de buckets.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
int ordenar_binsort(int arreglo[], size_t n) {
return ordenar_counting_sort(arreglo, n);
}Radixsort · código C
Ordena por dígitos en base 10, separando negativos y no negativos.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 exclusivamente si arreglo != NULL y n > 0; 0 de otro modo.
* @note No inspecciona elementos ni valida longitud real, alineacion, punteros colgantes o tamano de reservas.
*/
static int arreglo_valido(const int arreglo[], size_t n) {
return arreglo != NULL && n > 0;
}
/**
* @brief Ordena por conteo según un dígito decimal específico para Radix Sort (función auxiliar).
*
* @param arreglo Arreglo de enteros no negativos.
* @param n Número de elementos.
* @param exp Potencia de 10 que representa el dígito a procesar.
* @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR si falló memoria.
* @pre Buffer uint32_t escribible de n>0 entradas; n*sizeof(uint32_t) cabe en size_t; exp >0 es potencia decimal del caller.
* @note No valida NULL/exp ni longitud. Malloc fallido retorna ORDENAMIENTO_ERROR antes de escribir arreglo. Exito ordena estable por (valor/exp)%10, copia salida y libera temporal.
*/
static int counting_por_digito(uint32_t arreglo[], size_t n, uint32_t exp) {
size_t conteo[10] = {0}; uint32_t *salida; size_t i;
salida = (uint32_t *)malloc(n * sizeof(uint32_t));
if (salida == NULL) return ORDENAMIENTO_ERROR;
for (i = 0; i < n; ++i) ++conteo[(arreglo[i] / exp) % 10];
for (i = 1; i < 10; ++i) conteo[i] += conteo[i - 1];
for (i = n; i > 0; --i) {
uint32_t valor = arreglo[i - 1];
uint32_t digito = (valor / exp) % 10U;
salida[conteo[digito] - 1] = valor;
--conteo[digito];
}
for (i = 0; i < n; ++i) arreglo[i] = salida[i];
free(salida);
return ORDENAMIENTO_OK;
}
/**
* @brief Ordena un arreglo usando Radix Sort LSD en base 10.
*
* Esta implementación acepta enteros negativos separándolos de los no negativos,
* ordenando magnitudes y recombinando al final.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR ante arreglo NULL, n == 0 o fallo de memoria.
* @note Base 10, O(d(n+10)) tiempo y O(n+10) memoria. Conteo por digito estable; la inversion final del grupo negativo no garantiza estabilidad de registros negativos iguales. INT_MIN usa magnitud uint32_t y recomposicion protegida.
* @note Arreglo NULL o n==0 no se procesa; funciones int retornan ERROR y funciones void no comunican estado.
*/
int ordenar_radixsort(int arreglo[], size_t n) {
uint32_t *negativos, *positivos; size_t cant_negativos = 0, cant_positivos = 0, i, indice;
if (!arreglo_valido(arreglo, n)) return ORDENAMIENTO_ERROR;
negativos = (uint32_t *)malloc(n * sizeof(uint32_t));
positivos = (uint32_t *)malloc(n * sizeof(uint32_t));
if (negativos == NULL || positivos == NULL) { free(negativos); free(positivos); return ORDENAMIENTO_ERROR; }
for (i = 0; i < n; ++i) {
if (arreglo[i] < 0) negativos[cant_negativos++] = 0U - (uint32_t)arreglo[i];
else positivos[cant_positivos++] = (uint32_t)arreglo[i];
}
if (cant_negativos > 0) {
uint32_t maximo = negativos[0], exp = 1U;
for (i = 1; i < cant_negativos; ++i) if (negativos[i] > maximo) maximo = negativos[i];
for (;;) {
if (!counting_por_digito(negativos, cant_negativos, exp)) { free(negativos); free(positivos); return ORDENAMIENTO_ERROR; }
if (exp > maximo / 10U) break;
exp *= 10U;
}
}
if (cant_positivos > 0) {
uint32_t maximo = positivos[0], exp = 1U;
for (i = 1; i < cant_positivos; ++i) if (positivos[i] > maximo) maximo = positivos[i];
if (maximo > 0U) for (;;) {
if (!counting_por_digito(positivos, cant_positivos, exp)) { free(negativos); free(positivos); return ORDENAMIENTO_ERROR; }
if (exp > maximo / 10U) break;
exp *= 10U;
}
}
indice = 0;
for (i = cant_negativos; i > 0; --i) {
uint32_t magnitud = negativos[i - 1];
arreglo[indice++] = magnitud == (uint32_t)INT_MAX + 1U ? INT_MIN : -(int)magnitud;
}
for (i = 0; i < cant_positivos; ++i) arreglo[indice++] = (int)positivos[i];
free(negativos); free(positivos);
return ORDENAMIENTO_OK;
}Imprimir arreglo (utilidad sin botón propio) · código C
Imprime el arreglo completo con formato de lista.
/**
* @brief Imprime un arreglo de enteros en una línea.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @pre Si arreglo no NULL y n>0, contiene n ints vivos legibles.
* @note NULL arreglo o n==0 imprime [] y salto de linea. No reserva/libera ni modifica datos.
*/
void imprimir_arreglo(const int arreglo[], size_t n) {
size_t i;
if (!arreglo_valido(arreglo, n)) { printf("[]\n"); return; }
printf("[");
for (i = 0; i < n; ++i) {
printf("%d", arreglo[i]);
if (i + 1 < n) printf(", ");
}
printf("]\n");
}Copiar arreglo (utilidad sin botón propio) · código C
Copia un arreglo origen en un destino con validaciones básicas.
/**
* @brief Copia los elementos de un arreglo origen hacia un arreglo destino.
*
* @param destino Arreglo destino.
* @param origen Arreglo origen.
* @param n Número de elementos a copiar.
* @return ORDENAMIENTO_OK si la copia fue correcta; ORDENAMIENTO_ERROR en caso contrario.
* @pre Buffers vivos de al menos n ints, destino escribible y origen legible, sin solapamiento; n*sizeof(int) representable en size_t.
* @note NULL buffers o n==0 retorna ORDENAMIENTO_ERROR sin copiar. Usa memcpy, no memmove; no admite buffers solapados ni valida longitud. No reserva/libera.
*/
int copiar_arreglo(int destino[], const int origen[], size_t n) {
if (destino == NULL || origen == NULL || n == 0) return ORDENAMIENTO_ERROR;
memcpy(destino, origen, n * sizeof(int));
return ORDENAMIENTO_OK;
}Probar algoritmo void (utilidad del llamador) · código C
Ejecuta y muestra algoritmos que no retornan estado (void).
/**
* @brief Ejecuta y muestra un algoritmo de ordenamiento sobre una copia del arreglo base.
*
* @param nombre Nombre descriptivo del algoritmo.
* @param ordenar Función de ordenamiento que no retorna estado.
* @param base Arreglo base.
* @param n Número de elementos.
* @pre nombre es cadena viva terminada en NUL; base contiene n ints legibles, n*sizeof(int) representable. Callback valido recibe copia prestada, no la libera ni retiene; se cumplen sus limites particulares.
* @note NULL nombre/callback/base o n==0 no hace nada. Malloc fallido imprime error. Copia base, ejecuta callback, imprime copia y la libera; base queda intacta bajo precondiciones.
*/
void probar_algoritmo_void(const char *nombre, void (*ordenar)(int[], size_t), const int base[], size_t n) {
int *copia;
if (nombre == NULL || ordenar == NULL || !arreglo_valido(base, n)) return;
copia = (int *)malloc(n * sizeof(int));
if (copia == NULL) { printf("%s: error de memoria\n", nombre); return; }
copiar_arreglo(copia, base, n);
ordenar(copia, n);
printf("%-18s: ", nombre);
imprimir_arreglo(copia, n);
free(copia);
}Probar algoritmo con estado (utilidad del llamador) · código C
Ejecuta y muestra algoritmos que retornan ORDENAMIENTO_OK/ERROR.
/**
* @brief Ejecuta y muestra un algoritmo de ordenamiento que retorna estado.
*
* @param nombre Nombre descriptivo del algoritmo.
* @param ordenar Función de ordenamiento que retorna ORDENAMIENTO_OK o ORDENAMIENTO_ERROR.
* @param base Arreglo base.
* @param n Número de elementos.
* @pre nombre es cadena viva terminada en NUL; base contiene n ints legibles, n*sizeof(int) representable. Callback valido recibe copia prestada, no la libera ni retiene; se cumplen sus limites particulares.
* @note NULL nombre/callback/base o n==0 no hace nada. Error de malloc imprime diagnostico; callback con retorno cero imprime error y libera copia sin imprimir arreglo. Exito no cero imprime copia y la libera.
*/
void probar_algoritmo_int(const char *nombre, int (*ordenar)(int[], size_t), const int base[], size_t n) {
int *copia;
if (nombre == NULL || ordenar == NULL || !arreglo_valido(base, n)) return;
copia = (int *)malloc(n * sizeof(int));
if (copia == NULL) { printf("%s: error de memoria\n", nombre); return; }
copiar_arreglo(copia, base, n);
if (!ordenar(copia, n)) { printf("%s: error al ordenar\n", nombre); free(copia); return; }
printf("%-18s: ", nombre);
imprimir_arreglo(copia, n);
free(copia);
}