Browse Source

implement divide and conquer

Chris Cromer 7 months ago
parent
commit
6ac113d408
Signed by: Chris Cromer <chris@cromer.cl> GPG Key ID: 39CC813FF3C8708A
4 changed files with 156 additions and 70 deletions
  1. 1
    1
      src/distance.c
  2. 146
    53
      src/divide_and_conquer.c
  3. 6
    13
      src/points.c
  4. 3
    3
      test/test.c

+ 1
- 1
src/distance.c View File

@@ -23,5 +23,5 @@
23 23
  * @return Retorna la distancia entre los 2 puntos
24 24
  */
25 25
 double distance(point_t point1, point_t point2) {
26
-	return sqrt(pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2));
26
+	return pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2);
27 27
 }

+ 146
- 53
src/divide_and_conquer.c View File

@@ -14,74 +14,167 @@
14 14
  */
15 15
 
16 16
 #include <stdlib.h>
17
+#include <string.h>
18
+#include <math.h>
19
+#include <float.h>
17 20
 #include "points.h"
18 21
 #include "brute_force.h"
19 22
 #include "distance.h"
20 23
 
21 24
 /**
22
- * Encontrar los 2 puntos más cercano usando el metodo de dividir para conquistar
23
- * @param point_ts Los puntos a calcular
24
- * @param n La cantidad de puntos en el array point_ts
25
- * @param minimum_dist La distancia minimo encontrado
26
- * @return Retorna los 2 puntos mas cercanos
25
+ * Comparar 2 double para ver cual es mayor o si son iguales
26
+ * @param a El primer double a comparar
27
+ * @param b El segundo double a comparar
28
+ * @return Retorna 1 si a es mayor de b, -1 si a es menor de b ó 0 si son igual
27 29
  */
28
-int compareX(const void* a, const void* b){    //ordena el arreglo de puntos de acuerdo a X
29
-	    point_t *p1 = (point_t *)a,  *p2 = (point_t *)b; 
30
-	    return (p1->x - p2->x); 
30
+int compare_double(double a, double b) {
31
+	if (a > b) {
32
+		return 1;
33
+	}
34
+	else if (a < b) {
35
+		return -1;
36
+	}
37
+	else {
38
+		return 0;
39
+	}
31 40
 }
32 41
 
33
-int compareY(const void* a, const void* b){     //ordena el arreglo de puntos de acuerdo a Y
34
-	    point_t *p1 = (point_t *)a,   *p2 = (point_t *)b; 
35
-	    return (p1->y - p2->y); 
42
+/**
43
+ * Comparar los el eje x de 2 puntos
44
+ * @param a El primer punto a comparar
45
+ * @param b El segundo punto a comparar
46
+ * @return Retorna la comparación entre los 2 puntos
47
+ */
48
+int compare_x(const void * a, const void * b) {
49
+	return compare_double((*(point_t *) a).x, (*(point_t *) b).x);
36 50
 }
37 51
 
38
-double min(double x, double y){  // Función para encontrar el mayor entre dos valores flotantes
39
-	return (x < y)? x : y; 
52
+/**
53
+ * Comparar los el eje y de 2 puntos
54
+ * @param a El primer punto a comparar
55
+ * @param b El segundo punto a comparar
56
+ * @return Retorna la comparación entre los 2 puntos
57
+ */
58
+int compare_y(const void * a, const void * b) {
59
+	return compare_double((*(point_t *) a).y, (*(point_t *) b).y);
40 60
 }
41 61
 
42
-void stripClosest(point_t *strip, int n, double *minimum_dist, point_t *closest_pair) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado
43
-{ 
44
-	  	double dist;
45
-	    qsort(strip, n, sizeof(point_t), compareY);  
46
-	  
47
-	    for (int i = 0; i < n; ++i) 
48
-	        for (int j = i+1; j < n && (strip[j].y - strip[i].y) < *minimum_dist; ++j) 
49
-	            if ((dist = distance(strip[i],strip[j])) < *minimum_dist){
50
-	                *minimum_dist = dist;
51
-					closest_pair[0] = strip[i];
52
-					closest_pair[1] = strip[j];
53
-	            }
54
-} 
55
-
56
-double closestUtil(point_t *P, int n, double *minimum_dist, point_t *closest_pair){ // Función para encontrar la distancia más corta entre puntos
57
-		    int mid = n/2; 
58
-		    point_t midpoint_t = P[mid]; 
59
-		  	
60
-		    // Consider the vertical line passing through the middle point_t 
61
-		    // calculate the smallest distance dl on left of middle point_t and 
62
-		    // dr on right side 
63
-		    double dl = closestUtil(P, mid, minimum_dist, closest_pair); 
64
-		    double dr = closestUtil(P + mid, n-mid, minimum_dist, closest_pair); 
65
-		  
66
-		    double d = min(dl, dr); // Encontrar la distancia minima de dos puntos
67
-
68
-		    /* Crea un arreglo que contiene los puntos cercanos, mas cerca que d*/
69
-		    point_t strip[n]; 
70
-		    int j = 0; 
71
-		    for (int i = 0; i < n; i++) 
72
-		        if (abs(P[i].x - midpoint_t.x) < d) 
73
-		            strip[j] = P[i], j++; 
74
-
75
-		    /*Encontrar el punto más cercano en la cinta, retornando el minimo de d y el más cercano 
76
-		    	distance es strip[]*/
77
-		    *minimum_dist = min(d, stripClosest(strip, j, minimum_dist, closest_pair) );
78
-		    return *minimum_dist;
79
-} 
62
+/**
63
+ * El algoritmo de encontrar 2 puntos recursivo usando divide and conquer
64
+ * @param points_x Los puntos ordenado en el eje x
65
+ * @param nx La cantidad de puntos en el array points_y
66
+ * @param points_y Los puntos ordenado en el eje y
67
+ * @param ny La cantidad de puntos en el array points_y
68
+ * @param closest_pair Las 2 pares de puntos mas cercano
69
+ * @return Retorna la distance entre los dos puntos mas cercano
70
+ */
71
+double divide_and_conquer_run(point_t *points_x, unsigned int nx, point_t *points_y, unsigned int ny, point_t *closest_pair) {
72
+	int left;
73
+	int right;
74
+	int i;
75
+	double mid;
76
+	double d = DBL_MAX;
77
+	double min_d = DBL_MAX;
78
+	double x0;
79
+	double x1;
80
+	double x;
81
+	point_t *closest_pair2;
82
+	point_t *points_y2;
83
+	if (nx <= 4) {
84
+		closest_pair2 = brute_force(points_x, nx, &d);
85
+		closest_pair[0] = closest_pair2[0];
86
+		closest_pair[1] = closest_pair2[1];
87
+		return d;
88
+	}
89
+
90
+	closest_pair2 = malloc(sizeof(point_t) * 2);
91
+	points_y2 = malloc(sizeof(point_t) * ny);
92
+	mid = points_x[nx / 2].x;
93
+
94
+	left = -1;
95
+	right = ny;
96
+	for (i = 0; i < ny; i++) {
97
+		if (points_y[i].x < mid) {
98
+			points_y2[++left] = points_y[i];
99
+		}
100
+		else {
101
+			points_y2[--right]= points_y[i];
102
+		}
103
+	}
104
+
105
+	for (i = ny - 1; right < i; right ++, i--) {
106
+		closest_pair2[0] = points_y2[right];
107
+		points_y2[right] = points_y2[i];
108
+		points_y2[i] = closest_pair2[0];
109
+	}
110
+
111
+	min_d = divide_and_conquer_run(points_x, nx / 2, points_y2, left + 1, closest_pair);
112
+	d = divide_and_conquer_run(points_x + nx / 2, nx - nx / 2, points_y2 + left + 1, ny - left - 1, closest_pair2);
80 113
 
114
+	if (d < min_d) {
115
+		min_d = d;
116
+		closest_pair[0] = closest_pair2[0];
117
+		closest_pair[1] = closest_pair2[1];
118
+	}
119
+	d = sqrt(min_d);
120
+	free(closest_pair2);
121
+
122
+	left = -1; right = ny;
123
+	for (i = 0; i < ny; i++) {
124
+		x = points_y[i].x - mid;
125
+		if (x <= -d || x >= d) {
126
+			continue;
127
+		}
128
+		if (x < 0) {
129
+			points_y2[++left]  = points_y[i];
130
+		}
131
+		else {
132
+			points_y2[--right] = points_y[i];
133
+		}
134
+	}
135
+
136
+	while (left >= 0) {
137
+		x0 = points_y2[left].y + d;
138
+
139
+		while (right < ny && points_y2[right].y > x0) {
140
+			right ++;
141
+		}
142
+		if (right >= ny) {
143
+			break;
144
+		}
145
+
146
+		x1 = points_y2[left].y - d;
147
+		for (i = right; i < ny && points_y2[i].y > x1; i++)
148
+			if ((x = distance(points_y2[left], points_y2[i])) < min_d) {
149
+				min_d = x;
150
+				closest_pair[0] = points_y2[left];
151
+				closest_pair[1] = points_y2[i];
152
+			}
153
+		left--;
154
+	}
155
+
156
+	free(points_y2);
157
+	return min_d;
158
+}
159
+
160
+/**
161
+ * Encontrar los 2 puntos más cercano usando el metodo de dividir para conquistar
162
+ * @param point_t Los puntos a calcular
163
+ * @param n La cantidad de puntos en el array point_ts
164
+ * @param minimum_dist La distancia minimo encontrado
165
+ * @return Retorna los 2 puntos mas cercanos
166
+ */
81 167
 point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) {
82 168
 	point_t *closest_pair = malloc(sizeof(point_t) * 2);
83
-	qsort(points, n, sizeof(point_t), compareX); 
84
-	closestUtil(points, n, minimum_dist, closest_pair); //Usa la funcion recursiva closestUtil para encontrar la distancia minima
169
+	point_t *points_x = malloc(sizeof(point_t) * n);
170
+	point_t *points_y = malloc(sizeof(point_t) * n);
171
+	memcpy(points_x, points, sizeof(point_t) * n);
172
+	memcpy(points_y, points, sizeof(point_t) * n);
173
+	qsort(points_x, n, sizeof(point_t), compare_x);
174
+	qsort(points_y, n, sizeof(point_t), compare_y);
175
+	*minimum_dist = divide_and_conquer_run(points_x, n, points_y, n, closest_pair);
176
+	free(points_x);
177
+	free(points_y);
85 178
 	return closest_pair;
86 179
 }
87 180
 

+ 6
- 13
src/points.c View File

@@ -18,6 +18,7 @@
18 18
 #include <getopt.h>
19 19
 #include <string.h>
20 20
 #include <float.h>
21
+#include <math.h>
21 22
 #include "points.h"
22 23
 #include "distance.h"
23 24
 #include "timer.h"
@@ -166,26 +167,18 @@ int main (int argc, char **argv) {
166 167
 		end_algorithm();
167 168
 		fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y);
168 169
 		fprintf(stdout, "point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y);
169
-		fprintf(stdout, "distance: %lf\n\n", dist);
170
+		fprintf(stdout, "distance: %lf\n\n", sqrt(dist));
170 171
 		free(closest_points);
171 172
 		closest_points = NULL;
172 173
 	}
173 174
 
174 175
 	if (divide) {
175
-		if (n <= 3) {
176
-			fprintf(stderr, "Divide and conquer necesita 4 o mas puntos!\nSe utilizará Brute Force como alternativa!\n");
177
-			start_algorithm("Brute force corriendo... ", n);
178
-			closest_points = brute_force(points, n, &dist);
179
-			end_algorithm();
180
-		}
181
-		else {
182
-			start_algorithm("Divide and conquer corriendo... ", n);
183
-			closest_points = divide_and_conquer(points, n, &dist);
184
-			end_algorithm();
185
-		}
176
+		start_algorithm("Divide and conquer corriendo... ", n);
177
+		closest_points = divide_and_conquer(points, n, &dist);
178
+		end_algorithm();
186 179
 		fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y);
187 180
 		fprintf(stdout, "point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y);
188
-		fprintf(stdout, "distance: %lf\n", dist);
181
+		fprintf(stdout, "distance: %lf\n", sqrt(dist));
189 182
 		free(closest_points);
190 183
 		closest_points = NULL;
191 184
 	}

+ 3
- 3
test/test.c View File

@@ -30,7 +30,7 @@
30 30
  * @param d2 El segudno double
31 31
  * @return Retorna 1 si son igual o 0 sino
32 32
  */
33
-int compare_double(double d1, double d2) {
33
+inline int compare_double(double d1, double d2) {
34 34
 	double precision = 0.000000001;
35 35
 	if (((d1 - precision) < d2) && ((d1 + precision) > d2)) {
36 36
 		return 1;
@@ -72,7 +72,7 @@ int main(int argc, char **argv) {
72 72
 		fprintf(stdout, "\tbrute force: ");
73 73
 		fflush(stdout);
74 74
 		brute_force(points, n, &dist);
75
-		if (compare_double(dist, 0.067687840)) {
75
+		if (compare_double(sqrt(dist), 0.067687840)) {
76 76
 			fprintf(stdout, "passed\n");
77 77
 			passed++;
78 78
 		}
@@ -90,7 +90,7 @@ int main(int argc, char **argv) {
90 90
 		fprintf(stdout, "\tdivide and conquer: ");
91 91
 		fflush(stdout);
92 92
 		divide_and_conquer(points, n, &dist);
93
-		if (compare_double(dist, 0.067687840)) {
93
+		if (compare_double(sqrt(dist), 0.067687840)) {
94 94
 			fprintf(stdout, "passed\n");
95 95
 			passed++;
96 96
 		}

Loading…
Cancel
Save