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

  1. Predice si la siguiente comparación requiere intercambiar valores.
  2. Observa los índices activos y distingue comparación de escritura.
  3. 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

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

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

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

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

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);
}

Ir a la visualización