Browse Source

Make bitonic work for non powers of 2 (#24)

Chris Cromer 7 months ago
parent
commit
03c1305f57
2 changed files with 134 additions and 22 deletions
  1. 88
    11
      src/bitonic_sort.c
  2. 46
    11
      test/test.c

+ 88
- 11
src/bitonic_sort.c View File

@@ -16,6 +16,39 @@
16 16
 #include "swap.h"
17 17
 
18 18
 /**
19
+ * Verificar si x es de 2^n
20
+ * @param x El valor a verificar
21
+ * @return Retorna 1 si es de 2^n ó 0 al contrario;
22
+ */
23
+int power_of_two(int n) {
24
+	if (n == 0) {
25
+		return 0;
26
+	}
27
+
28
+	while (n != 1) {
29
+		if (n % 2 != 0) {
30
+			return 0;
31
+		}
32
+		n = n / 2;
33
+	}
34
+	return 1;
35
+}
36
+
37
+/**
38
+ * Buscar un valor que es de potencia de 2 pero menor que n
39
+ * @param n El valor de n
40
+ * @return Un potencia de 2 que es menor que n
41
+ */
42
+int greatest_power_of_two_less_than(int n) {
43
+	int k = 1;
44
+	while (k > 0 && k < n) {
45
+		k = (int) ((unsigned int) k << 1);
46
+	}
47
+	k = (int) ((unsigned int) k >> 1);
48
+	return (int) k;
49
+}
50
+
51
+/**
19 52
  * Comparar y intercambiar los valores para darle orden
20 53
  * @param i El primer indice a comparar
21 54
  * @param j El segundo indice a comparar
@@ -31,16 +64,16 @@ void compare(int i, int j, int dir, int *array) { //
31 64
 /**
32 65
  * Unir la secuencia
33 66
  * @param low El parte inferior
34
- * @param c El parte superior
67
+ * @param c El parte superior n
35 68
  * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
36 69
  * @param array El array a ordenar
37 70
  */
38
-void bitonicmerge(int low, int c, int dir, int *array) {
71
+void bitonicmerge(int low, int n, int dir, int *array) {
39 72
 	int i;
40 73
 	int k;
41 74
 
42
-	if (c > 1){
43
-		k = c / 2;
75
+	if (n > 1) {
76
+		k = n / 2;
44 77
 		for (i = low; i < low + k; i++){
45 78
 			compare(i, i + k, dir, array);
46 79
 		}
@@ -50,20 +83,59 @@ void bitonicmerge(int low, int c, int dir, int *array) {
50 83
 }
51 84
 
52 85
 /**
86
+ * Unir la secuencia cuando n no es de potencia 2
87
+ * @param low El parte inferior
88
+ * @param c El parte superior n
89
+ * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
90
+ * @param array El array a ordenar
91
+ */
92
+void bitonicmerge_no2(int low, int n, int dir, int *array) {
93
+	int i;
94
+	int k;
95
+
96
+	if (n > 1) {
97
+		k = greatest_power_of_two_less_than(n);
98
+		for (i = low; i < low + n-k; i++){
99
+			compare(i, i + k, dir, array);
100
+		}
101
+		bitonicmerge_no2(low, k, dir, array);
102
+		bitonicmerge_no2(low + k, n - k, dir, array);
103
+	}
104
+}
105
+
106
+/**
53 107
  * Generar la secuencia bitonica en forma de piramide
54 108
  * @param low El parte inferior
55
- * @param c El parte superior
109
+ * @param c El parte superior n
56 110
  * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
57 111
  * @param array El array a ordenar
58 112
  */
59
-void recbitonic(int low, int c, int dir, int *array) {
113
+void recbitonic(int low, int n, int dir, int *array) {
60 114
 	int k;
61 115
 
62
-	if (c > 1){
63
-		k = c / 2;
116
+	if (n > 1){
117
+		k = n / 2;
64 118
 		recbitonic(low, k, 1, array);
65 119
 		recbitonic(low + k, k, 0, array);
66
-		bitonicmerge(low, c, dir, array);
120
+		bitonicmerge(low, n, dir, array);
121
+	}
122
+}
123
+
124
+/**
125
+ * Generar la secuencia bitonica en forma de piramide cuando n no es de potencia 2
126
+ * @param low El parte inferior
127
+ * @param c El parte superior n
128
+ * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
129
+ * @param array El array a ordenar
130
+ */
131
+void recbitonic_no2(int low, int n, int dir, int *array) {
132
+	int k;
133
+
134
+	if (n > 1){
135
+		k = n / 2;
136
+		recbitonic_no2(low, k, !dir, array);
137
+		recbitonic_no2(low + k, n - k, dir, array);
138
+		bitonicmerge_no2(low, n, dir, array);
67 139
 	}
68 140
 }
69 141
 
@@ -74,7 +146,12 @@ void recbitonic(int low, int c, int dir, int *array) {
74 146
  * @param dir La dirección a ordenar, 1 para ascendentemente o 0 por descendentamente
75 147
  */
76 148
 void sort(int *array, int n, int dir) {
77
-	recbitonic(0, n, dir, array);
149
+	if (power_of_two(n)) {
150
+		recbitonic(0, n, dir, array);
151
+	}
152
+	else {
153
+		recbitonic_no2(0, n, dir, array);
154
+	}
78 155
 }
79 156
 
80 157
 /**
@@ -83,5 +160,5 @@ void sort(int *array, int n, int dir) {
83 160
  * @param n El tamaño del array
84 161
  */
85 162
 void bitonic_sort(int *array, int n) {
86
-	 sort(array, n, 1);
163
+	sort(array, n, 1);
87 164
 }

+ 46
- 11
test/test.c View File

@@ -52,7 +52,8 @@ void cleanup() {
52 52
  * El programa de test
53 53
  */
54 54
 int main(int argc, char **argv) {
55
-	int n = 32768;
55
+	int n = 50000;
56
+	int n2 = 32768;
56 57
 	int i;
57 58
 	int gen;
58 59
 	int pass;
@@ -99,7 +100,7 @@ int main(int argc, char **argv) {
99 100
 
100 101
 	// Prepare for sort tests
101 102
 	for (i = 0; i < n; i++) {
102
-		test_case[i] = gen_rand(-100, 100);
103
+		test_case[i] = gen_rand(-1000000, 1000000);
103 104
 	}
104 105
 	memcpy(qarray, test_case, sizeof(int) * n);
105 106
 	qsort(qarray, n, sizeof(int), compar);
@@ -161,12 +162,12 @@ int main(int argc, char **argv) {
161 162
 		passed++;
162 163
 	}
163 164
 
164
-	 // Test bitonic sort
165
+	// Test selection sort
165 166
 	pass = 1;
166 167
 	memcpy(test_array, test_case, sizeof(int) * n);
167
-	fprintf(stdout, "\tbitonic sort: ");
168
+	fprintf(stdout, "\tselection sort: ");
168 169
 	fflush(stdout);
169
-	bitonic_sort(test_array, n);
170
+	selection_sort(test_array, n);
170 171
 	for (i = 0; i < n; i++) {
171 172
 		if (test_array[i] != qarray[i]) {
172 173
 			fprintf(stdout, "fail\n");
@@ -180,12 +181,12 @@ int main(int argc, char **argv) {
180 181
 		passed++;
181 182
 	}
182 183
 
183
-	// Test selection sort
184
+	// Test merge sort
184 185
 	pass = 1;
185 186
 	memcpy(test_array, test_case, sizeof(int) * n);
186
-	fprintf(stdout, "\tselection sort: ");
187
+	fprintf(stdout, "\tmerge sort: ");
187 188
 	fflush(stdout);
188
-	selection_sort(test_array, n);
189
+	merge_sort(test_array, n);
189 190
 	for (i = 0; i < n; i++) {
190 191
 		if (test_array[i] != qarray[i]) {
191 192
 			fprintf(stdout, "fail\n");
@@ -199,12 +200,12 @@ int main(int argc, char **argv) {
199 200
 		passed++;
200 201
 	}
201 202
 
202
-	// Test merge sort
203
+	// Test bitonic sort without 2^n
203 204
 	pass = 1;
204 205
 	memcpy(test_array, test_case, sizeof(int) * n);
205
-	fprintf(stdout, "\tmerge sort: ");
206
+	fprintf(stdout, "\tbitonic sort: ");
206 207
 	fflush(stdout);
207
-	merge_sort(test_array, n);
208
+	bitonic_sort(test_array, n);
208 209
 	for (i = 0; i < n; i++) {
209 210
 		if (test_array[i] != qarray[i]) {
210 211
 			fprintf(stdout, "fail\n");
@@ -218,6 +219,40 @@ int main(int argc, char **argv) {
218 219
 		passed++;
219 220
 	}
220 221
 
222
+	// Test bitonic sort with 2^n
223
+	pass = 1;
224
+	int *bitonic_test_case = malloc(sizeof(int) * n2);
225
+	if (bitonic_test_case == NULL) {
226
+		fprintf(stderr, "Error: Out of heap space!\n");
227
+		exit(1);
228
+	}
229
+	int *bitonic_test_array = malloc(sizeof(int) * n2);
230
+	if (bitonic_test_array == NULL) {
231
+		fprintf(stderr, "Error: Out of heap space!\n");
232
+		exit(1);
233
+	}
234
+	for (i = 0; i < n; i++) {
235
+		bitonic_test_case[i] = gen_rand(-1000000, 1000000);
236
+	}
237
+	memcpy(qarray, bitonic_test_case, sizeof(int) * n2);
238
+	qsort(qarray, n2, sizeof(int), compar);
239
+	memcpy(bitonic_test_array, bitonic_test_case, sizeof(int) * n2);
240
+	fprintf(stdout, "\tbitonic sort 2^n: ");
241
+	fflush(stdout);
242
+	bitonic_sort(bitonic_test_array, n2);
243
+	for (i = 0; i < n2; i++) {
244
+		if (bitonic_test_array[i] != qarray[i]) {
245
+			fprintf(stdout, "fail\n");
246
+			failed++;
247
+			pass = 0;
248
+			break;
249
+		}
250
+	}
251
+	if (pass) {
252
+		fprintf(stdout, "pass\n");
253
+		passed++;
254
+	}
255
+
221 256
 	fprintf(stdout, "%d tests passed\n", passed);
222 257
 	fprintf(stdout, "%d tests failed\n", failed);
223 258
 

Loading…
Cancel
Save