Documentos de Académico
Documentos de Profesional
Documentos de Cultura
*
* Programa c_test2
* ================
*
* Banco de pruebas para rutinas de ordenamiento y búsqueda.
*
* Autor: Ing. Héctor R. RamÃrez S.
* Fecha: 19/02/2018 22:00
*
* Sinopsis: 1. Acepta vectores de hasta 1000000 elementos.
* 2. Opera con datos de tipo entero largo.
* 3. Reconoce (por ahora) los algoritmos de ordenamiento:
* 3.1. Burbuja
* 3.2. Inserción
* 3.3. Selección
* 3.4. Heapsort
* 3.5. Shellsort, en dos modalidades:
* 3.5.1. Incrementos por mitad
* 3.5.2. Incrementos por 1, 4, 13, ..., 3*k+1
* 3.6. Quicksort
* 4. Reconoce (por ahora) el algoritmo de búsqueda binaria.
* 5. Genera las siguientes condiciones de prueba:
* 5.1. Ingreso manual de datos
* 5.2. Datos aleatorios
* 5.3. Datos en orden creciente
* 5.4. Datos en orden decreciente
* 5.5. Datos en distribución uniforme
* 6. Validación de todas las entradas.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
int main() {
char op, buf[MAXBUF], *pb;
long dur, i, j, lim, orig[MAXVEC];
time_t inic, term;
/*
* Entrada y validación de la longitud máxima del arreglo a ordenar.
*
* El número a ingresar debe ser positivo (cantidad de elementos en el
arreglo), incluso cero.
*
* Tarea para todos: Probar el proceso de validación ingresando las
entradas inválidas que se les ocurran, pero tomando nota para reportar
si
* ================ alguna no es validada (la deja pasar en lugar de
solicitar nuevo número).
*/
while (1) {
printf("Longitud del arreglo a ordenar: ");
WIPE(buf, MAXBUF)
fgets(buf, MAXBUF, stdin);
/*
* Usamos apuntador al arreglo buf para mostrar el uso de
apuntadores. Otra manera de implementarlo es por Ãndice (while buf[i] !=
'\n').
*/
for (pb = buf; *pb != '\n'; pb++)
if (!isdigit(*pb)) {
printf("Solo debe ingresar dÃgitos [0, 1, ..., 9]. '%c'
(%d) no es aceptable. Repita.\n", *pb, *pb);
break;
}
/*
* Sale del ciclo for anterior, pero pudo ser porque detectó entrada
no válida (ver break; previo).
*/
if (*pb == '\n') {
sscanf(buf, "%li", &lim); /* sscanf es como scanf pero
desde memoria en vez de dispositivo. %li representa entero largo. */
else break;
}
}
/*
* Entrada y validación de las condiciones de prueba. OBSERVACIÓN:
Puede ser MUY fastidioso el ingreso manual para arreglos de gran tamaño
(>100).
*/
while (1) {
WIPE(orig, MAXVEC)
i = 0;
while (i == 0) {
printf("Ingrese (m)anual, (a)leatorio, (c)reciente,
(d)ecreciente, (u)niforme o (q)uit: ");
op = ' ';
while ((op != 'M') && (op != 'm') &&
(op != 'A') && (op != 'a') &&
(op != 'C') && (op != 'c') &&
(op != 'D') && (op != 'd') &&
(op != 'U') && (op != 'u') &&
(op != 'Q') && (op != 'q')) {
WIPE(buf, MAXBUF)
fgets(buf, MAXBUF, stdin);
sscanf(buf, "%c", &op);
}
/*
* switch equivale a una cascada de if ... else if ... else
if ... else ...
*/
switch (op) {
case 'M':
case 'm':
/*
* Entrada y validación de elementos del arreglo
ingresados manualmente. Refleja exactamente lo explicado en clase sobre
este tema.
*/
for (i = 0; i < lim; i++) {
printf("Elemento %li: ", i);
WIPE(buf, MAXBUF)
fgets(buf, MAXBUF, stdin);
/*
* Primer caracter solo puede ser signo o dÃgito.
*/
if (*buf == '\n') {
printf("Tiene que ingresar ALGO. Entrada nula
no es aceptable. Repita.\n");
i--;
}
i--;
}
else {
/*
* Siguientes caracteres (desde el segundo en
adelante) solo pueden ser dÃgitos.
*/
for (pb = buf, pb++; *pb != '\n'; pb++)
if (!isdigit(*pb)) {
printf("Solo acepta dÃgitos [0,
1, ..., 9]. '%c' (%d) no es válido. Repita.\n", *pb, *pb);
i--;
}
/*
* El último caracter marca el momento de
convertir desde cadena de caracteres hasta entero largo.
*/
break;
case 'C':
case 'c':
for (i = 0; i < lim; i++)
orig[i] = 3*i + 1; /* Genera la secuencia
1, 4, 7, 10, 13, ... */
break;
case 'D':
case 'd':
for (i = 0; i < lim; i++)
orig[i] = lim - 3*i; /* Genera una secuencia
del tipo lim, lim-3, lim-6, lim-9, ... */
break;
case 'U':
case 'u':
for (i = 0; i < lim; i++)
orig[i] = MAXVEC; /* Genera una secuencia
del tipo MAXVEC, MAXVEC, MAXVEC, ... */
break;
case 'Q':
case 'q':
printf("Terminado.\n");
i = lim;
break;
/*
* Usamos el caso por defecto para reportar posibles errores
no detectados en el programa.
*/
default:
printf("Esto no deberÃa suceder (op = <%c> [%i]).\n",
op, op);
i = 1;
break;
}
}
/*
* ¿Se ha fijado que todos los casos anteriores (excepto el caso por
defecto) terminan con i == lim?
*
* A continuación recibe y valida la respuesta del usuario sobre la
impresión en pantalla del arreglo definido antes.
*/
if ((i == lim) &&
(op != 'Q') && (op != 'q')) {
printf("Desea ver el arreglo a ordenar (S/n)? "); /*
PELIGRO! MUY lento para arreglos de gran tamaño (>100) */
op = ' ';
while ((op != 'S') && (op != 's') &&
(op != 'N') && (op != 'n')) {
WIPE(buf, MAXBUF)
fgets(buf, MAXBUF, stdin);
sscanf(buf, "%c", &op);
if ((op != 'S') && (op != 's') && (op != 'N') && (op !=
'n'))
printf("Debe ingresar solo 'S' o 'N'. '%c' (%d) no es
aceptable. Repita.\n", op, op);
}
printf("\n");
}
}
/*
* A continuación recibe y valida el procedimiento de
ordenamiento deseado.
*/
printf("Ingrese (b)urbuja, (i)nserción, (s)elección,
(h)eapsort, (q)uicksort, shell(1) o shell(2): ");
op = ' ';
while ((op != 'B') && (op != 'b') &&
(op != 'I') && (op != 'i') &&
(op != 'S') && (op != 's') &&
(op != 'H') && (op != 'h') &&
(op != 'Q') && (op != 'q') &&
(op != '1') && (op != '2')) {
WIPE(buf, MAXBUF)
fgets(buf, MAXBUF, stdin);
sscanf(buf, "%c", &op);
/*
* Inicializa el contador de tiempo transcurrido para el
procedimiento de ordenamiento seleccionado.
*/
time(&inic);
printf("Iniciado en %li\n", inic);
/*
* Invoca el procedimiento de ordenamiento elegido por el
usuario.
*/
switch (op) {
case 'B':
case 'b':
bubble_sort(orig, lim);
break;
case 'I':
case 'i':
insertion_sort(orig, lim);
break;
case 'S':
case 's':
selection_sort(orig, lim);
break;
case 'H':
case 'h':
heapsort(orig, lim);
break;
case 'Q':
case 'q':
qsort(orig, lim, sizeof(orig[0]), compare_elements);
break;
case '1':
shell_sort(orig, lim);
break;
case '2':
shellsort(orig, lim);
break;
default:
printf("Se encontró op = %c (%i). Esto NO DEBERÃA
SUCEDER!\n", op, op);
break;
}
/*
* Finaliza el contador de tiempo transcurrido para el
procedimiento de ordenamiento seleccionado.
*/
time(&term);
printf("Terminado en %li\n", term);
/*
* La diferencia entre el tiempo final y el tiempo inicial es el
tiempo total transcurrido.
*/
dur = difftime(term, inic);
printf("Tiempo total empleado en ordenar %li elementos:
%li\n", lim, dur);
/*
* Valida que el arreglo resultante está realmente ordenado como
se desea.
*/
for (i = 0; i < (lim - 1); i++)
if (orig[i] > orig[i + 1]) {
printf("El arreglo está DESORDENADO en la posición
%li ((a[%li] = %li) > (a[%li] = %li)).\n", i, i, orig[i], i + 1, orig[i +
1]);
break;
}
/*
* A continuación recibe y valida la respuesta del usuario sobre
la impresión en pantalla del arreglo ordenado antes.
*/
printf("Desea ver el arreglo resultante (S/n)? "); /*
PELIGRO! MUY lento para arreglos de gran tamaño (>100) */
op = ' ';
while ((op != 'S') && (op != 's') &&
(op != 'N') && (op != 'n')) {
WIPE(buf, MAXBUF)
fgets(buf, MAXBUF, stdin);
sscanf(buf, "%c", &op);
printf("\n");
}
}
/*
* A continuación permite al usuario realizar búsqueda binaria
en el arreglo ordenado resultante.
*/
find_element(orig, lim);
}
else break;
}
}
le = 0;
ri = max - 1;
while (le <= ri) {
mi = (le + ri)/2;
else
return (0);
}
do {
printf("Ingrese elemento a buscar (o 'q' para finalizar): ");
WIPE(op, MAXBUF)
fgets(op, MAXBUF, stdin);
else
printf("Elemento %li no está en el arreglo.\n", target);
}
} while ((op[0] != 'Q') && (op[0] != 'q'));
}
vec[le + 1] = tm;
}
}
lv = (max >> 1) + 1;
ir = max - 1;
while (1) {
if (lv > 0)
tm = vec[--lv];
else {
tm = vec[ir];
vec[ir] = vec[0];
if (--ir == 0) {
vec[0] = tm;
break;
}
}
le = lv;
ri = lv + 1;
while (ri <= ir) {
if ((ri < ir) && (vec[ri] < vec[ri + 1])) ri++;
else break;
}
vec[le] = tm;
}
}
inc = 1;
do {
inc *= 3;
inc++;
} while (inc < max);
do {
inc /= 3;
for (le = inc - 1; le < max; le++) {
tm = vec[le];
ri = le;
else break;
vec[ri] = tm;
}
} while (inc > 1);
}
/*
* Rutina shellsort: Implementa el algoritmo de Shell para ordenamiento
de un vector vec de max elementos del tipo entero largo.
* ================
*
* Entrada: vec - Arreglo tipo entero largo.
* max - Longitud del arreglo vec.
*
* Procedimiento: A diferencia de otros procedimientos de ordenamiento,
el algoritmo de Shell emplea una distancia variable entre
* ------------- elementos a comparar. La primera vuelta emplea la mitad
de la longitud total del arreglo para comparar elementos
* a intercambiar, la segunda vuelta emplea la mitad de la
mitad y asà sucesivamente hasta que, en la última vuelta
* se comparan elementos consecutivos (distancia = 1).
*/
void shellsort(long* vec, unsigned long max) {
long le, ri, inc, tm;