diff --git a/src/bitonic_sort.c b/src/bitonic_sort.c index 0875231..e8fe6a9 100644 --- a/src/bitonic_sort.c +++ b/src/bitonic_sort.c @@ -15,6 +15,39 @@ #include "swap.h" +/** + * Verificar si x es de 2^n + * @param x El valor a verificar + * @return Retorna 1 si es de 2^n ó 0 al contrario; + */ +int power_of_two(int n) { + if (n == 0) { + return 0; + } + + while (n != 1) { + if (n % 2 != 0) { + return 0; + } + n = n / 2; + } + return 1; +} + +/** + * Buscar un valor que es de potencia de 2 pero menor que n + * @param n El valor de n + * @return Un potencia de 2 que es menor que n + */ +int greatest_power_of_two_less_than(int n) { + int k = 1; + while (k > 0 && k < n) { + k = (int) ((unsigned int) k << 1); + } + k = (int) ((unsigned int) k >> 1); + return (int) k; +} + /** * Comparar y intercambiar los valores para darle orden * @param i El primer indice a comparar @@ -31,16 +64,16 @@ void compare(int i, int j, int dir, int *array) { // /** * Unir la secuencia * @param low El parte inferior - * @param c El parte superior + * @param c El parte superior n * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente * @param array El array a ordenar */ -void bitonicmerge(int low, int c, int dir, int *array) { +void bitonicmerge(int low, int n, int dir, int *array) { int i; int k; - if (c > 1){ - k = c / 2; + if (n > 1) { + k = n / 2; for (i = low; i < low + k; i++){ compare(i, i + k, dir, array); } @@ -50,20 +83,59 @@ void bitonicmerge(int low, int c, int dir, int *array) { } /** - * Generar la secuencia bitonica en forma de piramide + * Unir la secuencia cuando n no es de potencia 2 * @param low El parte inferior - * @param c El parte superior + * @param c El parte superior n * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente * @param array El array a ordenar */ -void recbitonic(int low, int c, int dir, int *array) { +void bitonicmerge_no2(int low, int n, int dir, int *array) { + int i; int k; - if (c > 1){ - k = c / 2; + if (n > 1) { + k = greatest_power_of_two_less_than(n); + for (i = low; i < low + n-k; i++){ + compare(i, i + k, dir, array); + } + bitonicmerge_no2(low, k, dir, array); + bitonicmerge_no2(low + k, n - k, dir, array); + } +} + +/** + * Generar la secuencia bitonica en forma de piramide + * @param low El parte inferior + * @param c El parte superior n + * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente + * @param array El array a ordenar + */ +void recbitonic(int low, int n, int dir, int *array) { + int k; + + if (n > 1){ + k = n / 2; recbitonic(low, k, 1, array); recbitonic(low + k, k, 0, array); - bitonicmerge(low, c, dir, array); + bitonicmerge(low, n, dir, array); + } +} + +/** + * Generar la secuencia bitonica en forma de piramide cuando n no es de potencia 2 + * @param low El parte inferior + * @param c El parte superior n + * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente + * @param array El array a ordenar + */ +void recbitonic_no2(int low, int n, int dir, int *array) { + int k; + + if (n > 1){ + k = n / 2; + recbitonic_no2(low, k, !dir, array); + recbitonic_no2(low + k, n - k, dir, array); + bitonicmerge_no2(low, n, dir, array); } } @@ -74,7 +146,12 @@ void recbitonic(int low, int c, int dir, int *array) { * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente */ void sort(int *array, int n, int dir) { - recbitonic(0, n, dir, array); + if (power_of_two(n)) { + recbitonic(0, n, dir, array); + } + else { + recbitonic_no2(0, n, dir, array); + } } /** @@ -83,5 +160,5 @@ void sort(int *array, int n, int dir) { * @param n El tamaño del array */ void bitonic_sort(int *array, int n) { - sort(array, n, 1); + sort(array, n, 1); } diff --git a/test/test.c b/test/test.c index 854662d..bf8368e 100644 --- a/test/test.c +++ b/test/test.c @@ -52,7 +52,8 @@ void cleanup() { * El programa de test */ int main(int argc, char **argv) { - int n = 32768; + int n = 50000; + int n2 = 32768; int i; int gen; int pass; @@ -99,7 +100,7 @@ int main(int argc, char **argv) { // Prepare for sort tests for (i = 0; i < n; i++) { - test_case[i] = gen_rand(-100, 100); + test_case[i] = gen_rand(-1000000, 1000000); } memcpy(qarray, test_case, sizeof(int) * n); qsort(qarray, n, sizeof(int), compar); @@ -156,25 +157,6 @@ int main(int argc, char **argv) { break; } } - if (pass) { - fprintf(stdout, "pass\n"); - passed++; - } - - // Test bitonic sort - pass = 1; - memcpy(test_array, test_case, sizeof(int) * n); - fprintf(stdout, "\tbitonic sort: "); - fflush(stdout); - bitonic_sort(test_array, n); - for (i = 0; i < n; i++) { - if (test_array[i] != qarray[i]) { - fprintf(stdout, "fail\n"); - failed++; - pass = 0; - break; - } - } if (pass) { fprintf(stdout, "pass\n"); passed++; @@ -218,6 +200,59 @@ int main(int argc, char **argv) { passed++; } + // Test bitonic sort without 2^n + pass = 1; + memcpy(test_array, test_case, sizeof(int) * n); + fprintf(stdout, "\tbitonic sort: "); + fflush(stdout); + bitonic_sort(test_array, n); + for (i = 0; i < n; i++) { + if (test_array[i] != qarray[i]) { + fprintf(stdout, "fail\n"); + failed++; + pass = 0; + break; + } + } + if (pass) { + fprintf(stdout, "pass\n"); + passed++; + } + + // Test bitonic sort with 2^n + pass = 1; + int *bitonic_test_case = malloc(sizeof(int) * n2); + if (bitonic_test_case == NULL) { + fprintf(stderr, "Error: Out of heap space!\n"); + exit(1); + } + int *bitonic_test_array = malloc(sizeof(int) * n2); + if (bitonic_test_array == NULL) { + fprintf(stderr, "Error: Out of heap space!\n"); + exit(1); + } + for (i = 0; i < n; i++) { + bitonic_test_case[i] = gen_rand(-1000000, 1000000); + } + memcpy(qarray, bitonic_test_case, sizeof(int) * n2); + qsort(qarray, n2, sizeof(int), compar); + memcpy(bitonic_test_array, bitonic_test_case, sizeof(int) * n2); + fprintf(stdout, "\tbitonic sort 2^n: "); + fflush(stdout); + bitonic_sort(bitonic_test_array, n2); + for (i = 0; i < n2; i++) { + if (bitonic_test_array[i] != qarray[i]) { + fprintf(stdout, "fail\n"); + failed++; + pass = 0; + break; + } + } + if (pass) { + fprintf(stdout, "pass\n"); + passed++; + } + fprintf(stdout, "%d tests passed\n", passed); fprintf(stdout, "%d tests failed\n", failed);