Metodos de Ordenamiento
Descripcion del TAD
Arreglo lineal de enteros ordenado mediante metodos clasicos del TAD C. La simulacion resalta comparaciones, intercambios/movimientos, pivote, rangos y auxiliares. El modulo de ordenamiento opera sobre arreglos de enteros y compara metodos clasicos del TAD C. La ejecucion didactica muestra comparaciones, intercambios/movimientos, pivote, rangos activos y auxiliares.
Controles de ejecucion paso a paso
- Checkbox Interpretar codigo paso a paso: activado muestra traza completa; desactivado aplica resultado final.
- Controles disponibles: Reproducir, Anterior paso, Siguiente paso, Reiniciar.
- Velocidad de simulacion: slider de -2x a +2x.
- El resultado final del modo rapido debe coincidir con el ultimo paso del modo interpretado.
Atajos de teclado
- Alt + →: siguiente.
- Alt + ←: anterior.
- Alt + Inicio/Fin: inicio/final.
- Alt + P: pausar.
- Alt + R: reproducir o repetir.
Fichas por algoritmo
Intercambio directo
Objetivo: Ordenar comparando cada posición con las posteriores.
Estrategia: Compara cada par (i, j) y permuta cuando encuentra desorden.
Invariante y dominio: predice cada intercambio; explica el prefijo confirmado
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n²), promedio O(n²), peor O(n²); memoria O(1).
Seleccion directa
Objetivo: Seleccionar el mínimo del segmento pendiente en cada pasada.
Estrategia: Busca el minimo del tramo no ordenado y lo coloca en la posicion actual.
Invariante y dominio: identifica el mínimo provisional; justifica el prefijo ordenado
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n²), promedio O(n²), peor O(n²); memoria O(1).
Insercion directa
Objetivo: Insertar cada clave en un prefijo previamente ordenado.
Estrategia: Inserta cada elemento en su lugar desplazando mayores hacia la derecha.
Invariante y dominio: ubica el hueco; explica la estabilidad
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n), promedio O(n²), peor O(n²); memoria O(1).
Burbuja mejorada
Objetivo: Desplazar el mayor elemento hacia el final mediante comparaciones adyacentes.
Estrategia: Compara adyacentes y burbujea los mayores hacia el final en cada pasada.
Invariante y dominio: predice la frontera de pasada; explica la terminación temprana
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n), promedio O(n²), peor O(n²); memoria O(1).
Shell sort
Objetivo: Ordenar subsecuencias separadas por intervalos decrecientes.
Estrategia: Generaliza insercion usando saltos (gaps) decrecientes hasta 1.
Invariante y dominio: forma los grupos por intervalo; explica el paso final con intervalo uno
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor depende de gaps, promedio depende de gaps, peor O(n²); memoria O(1).
Quick sort
Objetivo: Particionar alrededor de un pivote y resolver recursivamente los subrangos.
Estrategia: Particiona por pivote y ordena recursivamente subarreglos.
Invariante y dominio: sigue i y j; reconstruye el árbol de llamadas
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n log n), promedio O(n log n), peor O(n²); memoria O(log n) promedio.
Merge sort
Objetivo: Dividir el arreglo y fusionar segmentos ordenados mediante memoria auxiliar.
Estrategia: Divide recursivamente y fusiona subarreglos ordenados usando auxiliar.
Invariante y dominio: reconstruye divisiones; explica una fusión estable
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n log n), promedio O(n log n), peor O(n log n); memoria O(n).
Heap sort
Objetivo: Construir un max-heap y extraer repetidamente su raíz.
Estrategia: Construye max-heap y extrae repetidamente la raiz al final del arreglo.
Invariante y dominio: verifica la propiedad de heap; distingue heap y sufijo ordenado
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n log n), promedio O(n log n), peor O(n log n); memoria O(1).
Counting sort
Objetivo: Ordenar reconstruyendo el arreglo desde frecuencias de valores.
Estrategia: Cuenta ocurrencias por rango de valores y reconstruye el arreglo.
Invariante y dominio: calcula una urna; explica el coste dependiente del rango
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n+k), promedio O(n+k), peor O(n+k); memoria O(k).
Binsort
Objetivo: Relacionar la distribución en urnas con la implementación C basada en conteos.
Estrategia: En este TAD delega en counting sort.
Invariante y dominio: explica la delegación; reconstruye desde urnas
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(n+k), promedio O(n+k), peor O(n+k); memoria O(k).
Radix sort
Objetivo: Ordenar por dígitos estables y recombinar correctamente los signos.
Estrategia: Ordena por digitos (LSD) y maneja negativos separando grupos.
Invariante y dominio: identifica el dígito activo; explica el tratamiento de negativos
Error frecuente: Confundir el estado parcial con el resultado final o ignorar los límites del rango activo.
Complejidad: mejor O(d(n+b)), promedio O(d(n+b)), peor O(d(n+b)); memoria O(n+b).
Glosario contextual
- Pivote
- Valor copiado que guía una partición de QuickSort.
- Estabilidad
- Conservación del orden relativo entre claves iguales.
- In-place
- Algoritmo que usa memoria auxiliar constante o no proporcional a la entrada.
- Heap
- Árbol completo representado en arreglo que mantiene una relación padre-hijos.
- Bucket o urna
- Grupo asociado a un valor o dígito durante una distribución.
- Complejidad
- Crecimiento teórico del trabajo o memoria al aumentar la entrada.
Operaciones soportadas
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- arreglo_valido
- imprimir_arreglo
- copiar_arreglo
- probar_algoritmo_void
- probar_algoritmo_int
Pendientes / discrepancias
- El SDD lista como candidatos burbuja/seleccion/insercion/shell/merge/quick/heap.
- El TAD real tambien incluye intercambio, counting sort, binsort y radixsort.
Estructura del TAD en C
#define ORDENAMIENTO_OK 1
#define ORDENAMIENTO_ERROR 0
void imprimir_arreglo(const int arreglo[], size_t n);
int copiar_arreglo(int destino[], const int origen[], size_t n);
void ordenar_intercambio(int arreglo[], size_t n);
void ordenar_seleccion(int arreglo[], size_t n);
void ordenar_insercion(int arreglo[], size_t n);
void ordenar_burbuja(int arreglo[], size_t n);
void ordenar_shell(int arreglo[], size_t n);
void ordenar_quicksort(int arreglo[], size_t n);
int ordenar_mergesort(int arreglo[], size_t n);
void ordenar_heapsort(int arreglo[], size_t n);
int ordenar_counting_sort(int arreglo[], size_t n);
int ordenar_binsort(int arreglo[], size_t n);
int ordenar_radixsort(int arreglo[], size_t n);
void probar_algoritmo_void(const char *nombre, void (*ordenar)(int[], size_t), const int base[], size_t n);
void probar_algoritmo_int(const char *nombre, int (*ordenar)(int[], size_t), const int base[], size_t n);
Metodos del TAD en C
Codigo C: intercambio
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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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.
*/
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]);
}
Codigo C: seleccion
Busca el minimo del tramo no ordenado y lo ubica en la posicion actual.
/**
* @brief Verifica si un arreglo puede procesarse.
*
* @param arreglo Arreglo de enteros.
* @param n Número de elementos del arreglo.
* @return 1 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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.
*/
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]);
}
}
Codigo C: insercion
Inserta cada clave en su posicion 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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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;
}
}
Codigo C: burbuja
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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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.
*/
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;
}
}
Codigo C: shell
Aplica insercion 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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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;
}
}
}
Codigo C: quicksort
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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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.
*/
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.
*/
void ordenar_quicksort(int arreglo[], size_t n) {
if (!arreglo_valido(arreglo, n)) return;
quicksort_recursivo(arreglo, 0, (int)n - 1);
}
Codigo C: mergesort
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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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.
*/
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 si falló memoria.
*/
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;
}
Codigo C: heapsort
Construye max-heap y extrae la raiz 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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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.
*/
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.
*/
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);
}
}
Codigo C: counting_sort
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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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 si falló memoria.
*/
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;
}
Codigo C: binsort
Delega en counting sort segun implementacion 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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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 si falló memoria.
*/
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 un arreglo usando Binsort o clasificación por urnas.
*
* @param arreglo Arreglo de enteros a ordenar.
* @param n Número de elementos del arreglo.
* @return ORDENAMIENTO_OK si se ordenó correctamente; ORDENAMIENTO_ERROR si falló memoria.
*/
int ordenar_binsort(int arreglo[], size_t n) {
return ordenar_counting_sort(arreglo, n);
}
Codigo C: radixsort
Ordena por digitos 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 si el arreglo es válido; 0 en caso contrario.
*/
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.
*/
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 si falló memoria.
*/
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;
}
Codigo C: imprimir_arreglo
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.
*/
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");
}
Codigo C: copiar_arreglo
Copia un arreglo origen en un destino con validaciones basicas.
/**
* @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.
*/
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;
}
Codigo C: probar_algoritmo_void
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.
*/
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);
}
Codigo C: probar_algoritmo_int
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.
*/
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 visualizacion