From 905d78b6a5a39414fc9dfc6c0ef29bf18b6227d0 Mon Sep 17 00:00:00 2001 From: Rodolfo Cuevas Date: Wed, 12 Dec 2018 11:43:12 -0300 Subject: [PATCH 1/9] cristobal ladron --- src/divide_and_conquer.c | 151 +++++++++++++++++++++++++++++++ src/include/divide_and_conquer.h | 19 ++++ test/Makefile | 2 +- test/test.c | 19 ++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/divide_and_conquer.c create mode 100644 src/include/divide_and_conquer.h diff --git a/src/divide_and_conquer.c b/src/divide_and_conquer.c new file mode 100644 index 0000000..26c438f --- /dev/null +++ b/src/divide_and_conquer.c @@ -0,0 +1,151 @@ +/* + * Copyright 2018 Christopher Cromer + * Copyright 2018 Rodolfo Cuevas + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include "points.h" +#include "brute_force.h" +#include "distance.h" + +/** + * Encontrar los 2 puntos más cercano usando el metodo de dividir para conquistar + * @param points Los puntos a calcular + * @param n La cantidad de puntos en el array points + * @param minimum_dist La distancia minimo encontrado + * @return Retorna los 2 puntos mas cercanos + */ +point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) { + + if (n <= 3) + return brute_force(points, n, &minimum_dist); + int compareX(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a X + Point *p1 = (Point *)a, *p2 = (Point *)b; + return (p1->x - p2->x); + } + + int compareY(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a Y + Point *p1 = (Point *)a, *p2 = (Point *)b; + return (p1->y - p2->y); + } + // Función para encontrar la distancia minima entre dos valores de tipo flotante + float min(float x, float y) + { + return (x < y)? x : y; + } + + // Función para encontrar la distancia entre los puntos más cerca del arreglo dado + float stripClosest(Point strip[], int size, float d) + { + float min = d; // inicializa en la distancia minima d + + qsort(strip, size, sizeof(Point), compareY); + + for (int i = 0; i < size; ++i) + for (int j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j) + if (distance(strip[i],strip[j]) < min) + min = dist(strip[i], strip[j]); + + return min; + } + + // Función para encontrar la distancia más corta entre puntos + float closestUtil(Point P[], int n) + { + // Si hay igual o menos puntos a 3 utilizará el de fuerza bruta + if (n <= 3) + return bruteForce(P, n); + ------ + int mid = n/2; + Point midPoint = P[mid]; + + // Consider the vertical line passing through the middle point + // calculate the smallest distance dl on left of middle point and + // dr on right side + float dl = closestUtil(P, mid); + float dr = closestUtil(P + mid, n-mid); + + // Find the smaller of two distances + float d = min(dl, dr); + + // Build an array strip[] that contains points close (closer than d) + // to the line passing through the middle point + Point strip[n]; + int j = 0; + for (int i = 0; i < n; i++) + if (abs(P[i].x - midPoint.x) < d) + strip[j] = P[i], j++; + + // Find the closest points in strip. Return the minimum of d and closest + // distance is strip[] + return min(d, stripClosest(strip, j, d) ); + } + + // The main functin that finds the smallest distance + // This method mainly uses closestUtil() + float closest(Point P[], int n) + { + qsort(P, n, sizeof(Point), compareX); + + // Use recursive function closestUtil() to find the smallest distance + return closestUtil(P, n); + } +return closest_pair; +} +-------- +float closestUtil(Point P[], int n) /*Función recursiva para encontrar la distancia más pequeña. El arreglo + P contiene todos los puntos ordenados respecto a la cordenada X */ +{ + int mid = n/2; + Point midPoint = P[mid]; + + // Consider the vertical line passing through the middle point + // calculate the smallest distance dl on left of middle point and + // dr on right side + float dl = closestUtil(P, mid); + float dr = closestUtil(P + mid, n-mid); + + // Find the smaller of two distances + float d = min(dl, dr); + + // Build an array strip[] that contains points close (closer than d) + // to the line passing through the middle point + Point strip[n]; + int j = 0; + for (int i = 0; i < n; i++) + if (abs(P[i].x - midPoint.x) < d) + strip[j] = P[i], j++; + + // Find the closest points in strip. Return the minimum of d and closest + // distance is strip[] + return min(d, stripClosest(strip, j, d) ); +} + +// The main functin that finds the smallest distance +// This method mainly uses closestUtil() +float closest(Point P[], int n) +{ + qsort(P, n, sizeof(Point), compareX); + + // Use recursive function closestUtil() to find the smallest distance + return closestUtil(P, n); +} + +// Driver program to test above functions +int main() +{ + Point P[] = {{2, 3}, {12, 30}, {40, 50}, {5, 1}, {12, 10}, {3, 4}}; + int n = sizeof(P) / sizeof(P[0]); + printf("The smallest distance is %f ", closest(P, n)); + return 0; +} \ No newline at end of file diff --git a/src/include/divide_and_conquer.h b/src/include/divide_and_conquer.h new file mode 100644 index 0000000..1614d70 --- /dev/null +++ b/src/include/divide_and_conquer.h @@ -0,0 +1,19 @@ +/* + * Copyright 2018 Christopher Cromer + * Copyright 2018 Rodolfo Cuevas + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _POINTS_DIVIDE_AND_CONQUER + #define _POINTS_DIVIDE_AND_CONQUER + point_t * divide_and_conquer(point_t *points, unsigned int n, double *dist); +#endif \ No newline at end of file diff --git a/test/Makefile b/test/Makefile index e01eebf..c9c1dd8 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,7 +4,7 @@ LDFLAGS=-lm SRC=test.c OBJ=$(SRC:.c=.o) -OBJ+=../src/read_file.o ../src/distance.o ../src/brute_force.o +OBJ+=../src/read_file.o ../src/distance.o ../src/brute_force.o ../src/divide_and_conquer.o all: test diff --git a/test/test.c b/test/test.c index 53ea290..8679b38 100644 --- a/test/test.c +++ b/test/test.c @@ -22,6 +22,7 @@ #include "points.h" #include "read_file.h" #include "brute_force.h" +#include "divide_and_conquer.h" /** * Comparar 2 double para ver si son casi igual @@ -81,6 +82,24 @@ int main(int argc, char **argv) { } } + if (failed > 0) { + fprintf(stdout, "\tdivide and conquer: failed\n"); + failed++; + } + else { + fprintf(stdout, "\tdivide and conquer: "); + fflush(stdout); + divide_and_conquer(points, n, &dist); + if (compare_double(dist, 0.067687840)) { + fprintf(stdout, "passed\n"); + passed++; + } + else { + fprintf(stdout, "failed\n"); + failed++; + } + } + fprintf(stdout, "%d tests passed\n", passed); fprintf(stdout, "%d tests failed\n", failed); From c200d74897a61809bfc14f5ed7e1be78baabf2ab Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 12 Dec 2018 11:48:14 -0300 Subject: [PATCH 2/9] add divide and conquer to makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 246921c..55ef255 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC=gcc CFLAGS=-Wall -Isrc/include -DDEBUG -g LDFLAGS=-lm -SRC=src/points.c src/timer.c src/read_file.c src/distance.c src/brute_force.c +SRC=src/points.c src/timer.c src/read_file.c src/distance.c src/brute_force.c src/divide_and_conquer.c OBJ=$(SRC:.c=.o) all: points informe From 2e3d2b43ee08bd77fe4db14efbf75388efe32b99 Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 12 Dec 2018 11:54:12 -0300 Subject: [PATCH 3/9] uncomment code in points.c --- src/points.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/points.c b/src/points.c index 8b049a7..5c58f24 100644 --- a/src/points.c +++ b/src/points.c @@ -172,13 +172,13 @@ int main (int argc, char **argv) { if (divide) { start_algorithm("Divide and conquer corriendo... ", n); - //closest_points = divide_and_conquer(points, n, &dist); + closest_points = divide_and_conquer(points, n, &dist); end_algorithm(); - /*printf("point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); + printf("point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); printf("point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y); printf("distance: %lf\n", dist); free(closest_points); - closest_points = NULL;*/ + closest_points = NULL; } free(points); From daf9d6cc4ad75096fa964cc001562613ce4309fc Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 12 Dec 2018 12:03:16 -0300 Subject: [PATCH 4/9] a few small fixes --- src/points.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/points.c b/src/points.c index 5c58f24..dc9d897 100644 --- a/src/points.c +++ b/src/points.c @@ -23,6 +23,7 @@ #include "timer.h" #include "read_file.h" #include "brute_force.h" +#include "divide_and_conquer.h" #define POINTS_VERSION "1.0.0" @@ -163,20 +164,28 @@ int main (int argc, char **argv) { start_algorithm("Brute force corriendo... ", n); closest_points = brute_force(points, n, &dist); end_algorithm(); - printf("point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); - printf("point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y); - printf("distance: %lf\n\n", dist); + fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); + fprintf(stdout, "point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y); + fprintf(stdout, "distance: %lf\n\n", dist); free(closest_points); closest_points = NULL; } if (divide) { - start_algorithm("Divide and conquer corriendo... ", n); - closest_points = divide_and_conquer(points, n, &dist); - end_algorithm(); - printf("point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); - printf("point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y); - printf("distance: %lf\n", dist); + if (n <= 3) { + fprintf(stderr, "Divide and conquer necesita 4 o mas puntos!\nSe utilizará Brute Force como alternativa!\n"); + start_algorithm("Brute force corriendo... ", n); + closest_points = brute_force(points, n, &dist); + end_algorithm(); + } + else { + start_algorithm("Divide and conquer corriendo... ", n); + closest_points = divide_and_conquer(points, n, &dist); + end_algorithm(); + } + fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); + fprintf(stdout, "point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y); + fprintf(stdout, "distance: %lf\n", dist); free(closest_points); closest_points = NULL; } From a72f55594bdb6611b1bd306dfc7da570bc3fa7dd Mon Sep 17 00:00:00 2001 From: Rodolfo Cuevas Date: Wed, 12 Dec 2018 12:09:56 -0300 Subject: [PATCH 5/9] =?UTF-8?q?limpi=C3=A9=20divide=20and=20conquer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/divide_and_conquer.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/divide_and_conquer.c b/src/divide_and_conquer.c index 26c438f..b846522 100644 --- a/src/divide_and_conquer.c +++ b/src/divide_and_conquer.c @@ -25,28 +25,23 @@ * @param minimum_dist La distancia minimo encontrado * @return Retorna los 2 puntos mas cercanos */ -point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) { - - if (n <= 3) - return brute_force(points, n, &minimum_dist); - int compareX(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a X +int compareX(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a X Point *p1 = (Point *)a, *p2 = (Point *)b; return (p1->x - p2->x); - } +} - int compareY(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a Y +int compareY(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a Y Point *p1 = (Point *)a, *p2 = (Point *)b; return (p1->y - p2->y); - } - // Función para encontrar la distancia minima entre dos valores de tipo flotante - float min(float x, float y) - { - return (x < y)? x : y; - } +} - // Función para encontrar la distancia entre los puntos más cerca del arreglo dado - float stripClosest(Point strip[], int size, float d) - { +float min(float x, float y){ // Función para encontrar la distancia minima entre dos valores de tipo flotante + return (x < y)? x : y; +} + + +float stripClosest(Point strip[], int size, float d) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado +{ float min = d; // inicializa en la distancia minima d qsort(strip, size, sizeof(Point), compareY); @@ -57,7 +52,14 @@ point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_di min = dist(strip[i], strip[j]); return min; - } +} + +point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) { + + if (n <= 3) + return brute_force(points, n, &minimum_dist); + + // Función para encontrar la distancia más corta entre puntos float closestUtil(Point P[], int n) From 00444c46f253f3fa1d75be1620c0d21194a99e0f Mon Sep 17 00:00:00 2001 From: Rodolfo Cuevas Date: Wed, 12 Dec 2018 12:26:33 -0300 Subject: [PATCH 6/9] sigo limpiando divide and conquer --- src/divide_and_conquer.c | 128 ++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 77 deletions(-) diff --git a/src/divide_and_conquer.c b/src/divide_and_conquer.c index b846522..a22f1f8 100644 --- a/src/divide_and_conquer.c +++ b/src/divide_and_conquer.c @@ -20,31 +20,54 @@ /** * Encontrar los 2 puntos más cercano usando el metodo de dividir para conquistar - * @param points Los puntos a calcular - * @param n La cantidad de puntos en el array points + * @param point_ts Los puntos a calcular + * @param n La cantidad de puntos en el array point_ts * @param minimum_dist La distancia minimo encontrado * @return Retorna los 2 puntos mas cercanos */ int compareX(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a X - Point *p1 = (Point *)a, *p2 = (Point *)b; + point_t *p1 = (point_t *)a, *p2 = (point_t *)b; return (p1->x - p2->x); } int compareY(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a Y - Point *p1 = (Point *)a, *p2 = (Point *)b; + point_t *p1 = (point_t *)a, *p2 = (point_t *)b; return (p1->y - p2->y); } -float min(float x, float y){ // Función para encontrar la distancia minima entre dos valores de tipo flotante +float min(float x, float y){ // Función para encontrar el mayor entre dos valores flotantes return (x < y)? x : y; } +float closestUtil(point_t P[], int n){ // Función para encontrar la distancia más corta entre puntos + int mid = n/2; + point_t midpoint_t = P[mid]; + + // Consider the vertical line passing through the middle point_t + // calculate the smallest distance dl on left of middle point_t and + // dr on right side + float dl = closestUtil(P, mid); + float dr = closestUtil(P + mid, n-mid); + + float d = min(dl, dr); // Encontrar la distancia minima de dos puntos + + /* Crea un arreglo que contiene los puntos cercanos, mas cerca que d*/ + point_t strip[n]; + int j = 0; + for (int i = 0; i < n; i++) + if (abs(P[i].x - midpoint_t.x) < d) + strip[j] = P[i], j++; + + /*Encontrar el punto más cercano en la cinta, retornando el minimo de d y el más cercano + distance es strip[]*/ + return min(d, stripClosest(strip, j, d) ); +} -float stripClosest(Point strip[], int size, float d) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado +float stripClosest(point_t strip[], int size, float d) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado { float min = d; // inicializa en la distancia minima d - qsort(strip, size, sizeof(Point), compareY); + qsort(strip, size, sizeof(point_t), compareY); for (int i = 0; i < size; ++i) for (int j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j) @@ -55,99 +78,50 @@ float stripClosest(Point strip[], int size, float d) // Función para encontrar } point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) { - - if (n <= 3) - return brute_force(points, n, &minimum_dist); + point_t *closest_pair = malloc(sizeof(point_t) * 2); - // Función para encontrar la distancia más corta entre puntos - float closestUtil(Point P[], int n) + float closest(point_t P[], int n) + { + qsort(P, n, sizeof(point_t), compareX); + return closestUtil(P, n); /*Uso recursivo de la funcion closestUtil() para encontrar la distancia más pequeña*/ + } + return closest_pair; + } + + float closestUtil(point_t P[], int n) /*Función recursiva para encontrar la distancia más pequeña. El arreglo + P contiene todos los puntos ordenados respecto a la cordenada X */ { - // Si hay igual o menos puntos a 3 utilizará el de fuerza bruta - if (n <= 3) - return bruteForce(P, n); - ------ int mid = n/2; - Point midPoint = P[mid]; - - // Consider the vertical line passing through the middle point - // calculate the smallest distance dl on left of middle point and - // dr on right side + point_t midpoint_t = P[mid]; + /*Considerando la linea vertical que pasa a travez del punto medio, calcula el distanca mas corta en dl + de la izquierda de la mitad y dr en el lado derecho*/ float dl = closestUtil(P, mid); float dr = closestUtil(P + mid, n-mid); // Find the smaller of two distances float d = min(dl, dr); - // Build an array strip[] that contains points close (closer than d) - // to the line passing through the middle point - Point strip[n]; + // Build an array strip[] that contains point_ts close (closer than d) + // to the line passing through the middle point_t + point_t strip[n]; int j = 0; for (int i = 0; i < n; i++) - if (abs(P[i].x - midPoint.x) < d) + if (abs(P[i].x - midpoint_t.x) < d) strip[j] = P[i], j++; - // Find the closest points in strip. Return the minimum of d and closest + // Find the closest point_ts in strip. Return the minimum of d and closest // distance is strip[] return min(d, stripClosest(strip, j, d) ); } // The main functin that finds the smallest distance // This method mainly uses closestUtil() - float closest(Point P[], int n) + float closest(point_t P[], int n) { - qsort(P, n, sizeof(Point), compareX); + qsort(P, n, sizeof(point_t), compareX); // Use recursive function closestUtil() to find the smallest distance return closestUtil(P, n); } -return closest_pair; -} --------- -float closestUtil(Point P[], int n) /*Función recursiva para encontrar la distancia más pequeña. El arreglo - P contiene todos los puntos ordenados respecto a la cordenada X */ -{ - int mid = n/2; - Point midPoint = P[mid]; - - // Consider the vertical line passing through the middle point - // calculate the smallest distance dl on left of middle point and - // dr on right side - float dl = closestUtil(P, mid); - float dr = closestUtil(P + mid, n-mid); - - // Find the smaller of two distances - float d = min(dl, dr); - - // Build an array strip[] that contains points close (closer than d) - // to the line passing through the middle point - Point strip[n]; - int j = 0; - for (int i = 0; i < n; i++) - if (abs(P[i].x - midPoint.x) < d) - strip[j] = P[i], j++; - - // Find the closest points in strip. Return the minimum of d and closest - // distance is strip[] - return min(d, stripClosest(strip, j, d) ); -} - -// The main functin that finds the smallest distance -// This method mainly uses closestUtil() -float closest(Point P[], int n) -{ - qsort(P, n, sizeof(Point), compareX); - - // Use recursive function closestUtil() to find the smallest distance - return closestUtil(P, n); -} - -// Driver program to test above functions -int main() -{ - Point P[] = {{2, 3}, {12, 30}, {40, 50}, {5, 1}, {12, 10}, {3, 4}}; - int n = sizeof(P) / sizeof(P[0]); - printf("The smallest distance is %f ", closest(P, n)); - return 0; -} \ No newline at end of file From b1c3c1aa3139eb062669356fa2e4e31c20b0a365 Mon Sep 17 00:00:00 2001 From: Rodolfo Cuevas Date: Wed, 12 Dec 2018 12:33:06 -0300 Subject: [PATCH 7/9] xd --- src/divide_and_conquer.c | 75 +++++++++------------------------------- 1 file changed, 17 insertions(+), 58 deletions(-) diff --git a/src/divide_and_conquer.c b/src/divide_and_conquer.c index a22f1f8..190ccb8 100644 --- a/src/divide_and_conquer.c +++ b/src/divide_and_conquer.c @@ -39,6 +39,20 @@ float min(float x, float y){ // Función para encontrar el mayor entre dos valo return (x < y)? x : y; } +float stripClosest(point_t strip[], int size, float d) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado +{ + float min = d; // inicializa en la distancia minima d + + qsort(strip, size, sizeof(point_t), compareY); + + for (int i = 0; i < size; ++i) + for (int j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j) + if (distance(strip[i],strip[j]) < min) + min = dist(strip[i], strip[j]); + + return min; +} + float closestUtil(point_t P[], int n){ // Función para encontrar la distancia más corta entre puntos int mid = n/2; point_t midpoint_t = P[mid]; @@ -62,66 +76,11 @@ float closestUtil(point_t P[], int n){ // Función para encontrar la distancia m distance es strip[]*/ return min(d, stripClosest(strip, j, d) ); } - -float stripClosest(point_t strip[], int size, float d) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado -{ - float min = d; // inicializa en la distancia minima d - - qsort(strip, size, sizeof(point_t), compareY); - - for (int i = 0; i < size; ++i) - for (int j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j) - if (distance(strip[i],strip[j]) < min) - min = dist(strip[i], strip[j]); - - return min; -} point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) { point_t *closest_pair = malloc(sizeof(point_t) * 2); + qsort(P, n, sizeof(point_t), compareX); + return closestUtil(P, n); //Usa la funcion recursiva closestUtil para encontrar la distancia minima +} - - float closest(point_t P[], int n) - { - qsort(P, n, sizeof(point_t), compareX); - return closestUtil(P, n); /*Uso recursivo de la funcion closestUtil() para encontrar la distancia más pequeña*/ - } - return closest_pair; - } - - float closestUtil(point_t P[], int n) /*Función recursiva para encontrar la distancia más pequeña. El arreglo - P contiene todos los puntos ordenados respecto a la cordenada X */ - { - int mid = n/2; - point_t midpoint_t = P[mid]; - /*Considerando la linea vertical que pasa a travez del punto medio, calcula el distanca mas corta en dl - de la izquierda de la mitad y dr en el lado derecho*/ - float dl = closestUtil(P, mid); - float dr = closestUtil(P + mid, n-mid); - - // Find the smaller of two distances - float d = min(dl, dr); - - // Build an array strip[] that contains point_ts close (closer than d) - // to the line passing through the middle point_t - point_t strip[n]; - int j = 0; - for (int i = 0; i < n; i++) - if (abs(P[i].x - midpoint_t.x) < d) - strip[j] = P[i], j++; - - // Find the closest point_ts in strip. Return the minimum of d and closest - // distance is strip[] - return min(d, stripClosest(strip, j, d) ); - } - - // The main functin that finds the smallest distance - // This method mainly uses closestUtil() - float closest(point_t P[], int n) - { - qsort(P, n, sizeof(point_t), compareX); - - // Use recursive function closestUtil() to find the smallest distance - return closestUtil(P, n); - } From e37384d18f5c5608f524c39268240f41dca0ab68 Mon Sep 17 00:00:00 2001 From: Rodolfo Cuevas Date: Wed, 12 Dec 2018 13:30:38 -0300 Subject: [PATCH 8/9] limpieza 101 --- src/divide_and_conquer.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/divide_and_conquer.c b/src/divide_and_conquer.c index 190ccb8..1f29a97 100644 --- a/src/divide_and_conquer.c +++ b/src/divide_and_conquer.c @@ -35,35 +35,35 @@ int compareY(const void* a, const void* b){ //ordena el arreglo de puntos de return (p1->y - p2->y); } -float min(float x, float y){ // Función para encontrar el mayor entre dos valores flotantes +double min(double x, double y){ // Función para encontrar el mayor entre dos valores flotantes return (x < y)? x : y; } -float stripClosest(point_t strip[], int size, float d) // Función para encontrar la distancia entre los puntos más cerca del arreglo dado +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 { - float min = d; // inicializa en la distancia minima d + double dist; + qsort(strip, n, sizeof(point_t), compareY); - qsort(strip, size, sizeof(point_t), compareY); - - for (int i = 0; i < size; ++i) - for (int j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j) - if (distance(strip[i],strip[j]) < min) - min = dist(strip[i], strip[j]); - - return min; + for (int i = 0; i < n; ++i) + for (int j = i+1; j < n && (strip[j].y - strip[i].y) < *minimum_dist; ++j) + if ((dist = distance(strip[i],strip[j])) < *minimum_dist){ + *minimum_dist = dist; + closest_pair[0] = strip[i]; + closest_pair[1] = strip[j]; + } } -float closestUtil(point_t P[], int n){ // Función para encontrar la distancia más corta entre puntos +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 int mid = n/2; point_t midpoint_t = P[mid]; - + // Consider the vertical line passing through the middle point_t // calculate the smallest distance dl on left of middle point_t and // dr on right side - float dl = closestUtil(P, mid); - float dr = closestUtil(P + mid, n-mid); + double dl = closestUtil(P, mid, minimum_dist, closest_pair); + double dr = closestUtil(P + mid, n-mid, minimum_dist, closest_pair); - float d = min(dl, dr); // Encontrar la distancia minima de dos puntos + double d = min(dl, dr); // Encontrar la distancia minima de dos puntos /* Crea un arreglo que contiene los puntos cercanos, mas cerca que d*/ point_t strip[n]; @@ -74,13 +74,15 @@ float closestUtil(point_t P[], int n){ // Función para encontrar la distancia m /*Encontrar el punto más cercano en la cinta, retornando el minimo de d y el más cercano distance es strip[]*/ - return min(d, stripClosest(strip, j, d) ); + *minimum_dist = min(d, stripClosest(strip, j, minimum_dist, closest_pair) ); + return *minimum_dist; } point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) { point_t *closest_pair = malloc(sizeof(point_t) * 2); - qsort(P, n, sizeof(point_t), compareX); - return closestUtil(P, n); //Usa la funcion recursiva closestUtil para encontrar la distancia minima + qsort(points, n, sizeof(point_t), compareX); + closestUtil(points, n, minimum_dist, closest_pair); //Usa la funcion recursiva closestUtil para encontrar la distancia minima + return closest_pair; } From 6ac113d4086f9c24862a606a33a8f59f2ae8cefa Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 12 Dec 2018 18:48:54 -0300 Subject: [PATCH 9/9] implement divide and conquer --- src/distance.c | 2 +- src/divide_and_conquer.c | 205 ++++++++++++++++++++++++++++----------- src/points.c | 19 ++-- test/test.c | 6 +- 4 files changed, 159 insertions(+), 73 deletions(-) diff --git a/src/distance.c b/src/distance.c index 9fb0c6c..16b9871 100644 --- a/src/distance.c +++ b/src/distance.c @@ -23,5 +23,5 @@ * @return Retorna la distancia entre los 2 puntos */ double distance(point_t point1, point_t point2) { - return sqrt(pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2)); + return pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2); } diff --git a/src/divide_and_conquer.c b/src/divide_and_conquer.c index 1f29a97..390edbe 100644 --- a/src/divide_and_conquer.c +++ b/src/divide_and_conquer.c @@ -14,74 +14,167 @@ */ #include +#include +#include +#include #include "points.h" #include "brute_force.h" #include "distance.h" +/** + * Comparar 2 double para ver cual es mayor o si son iguales + * @param a El primer double a comparar + * @param b El segundo double a comparar + * @return Retorna 1 si a es mayor de b, -1 si a es menor de b ó 0 si son igual + */ +int compare_double(double a, double b) { + if (a > b) { + return 1; + } + else if (a < b) { + return -1; + } + else { + return 0; + } +} + +/** + * Comparar los el eje x de 2 puntos + * @param a El primer punto a comparar + * @param b El segundo punto a comparar + * @return Retorna la comparación entre los 2 puntos + */ +int compare_x(const void * a, const void * b) { + return compare_double((*(point_t *) a).x, (*(point_t *) b).x); +} + +/** + * Comparar los el eje y de 2 puntos + * @param a El primer punto a comparar + * @param b El segundo punto a comparar + * @return Retorna la comparación entre los 2 puntos + */ +int compare_y(const void * a, const void * b) { + return compare_double((*(point_t *) a).y, (*(point_t *) b).y); +} + +/** + * El algoritmo de encontrar 2 puntos recursivo usando divide and conquer + * @param points_x Los puntos ordenado en el eje x + * @param nx La cantidad de puntos en el array points_y + * @param points_y Los puntos ordenado en el eje y + * @param ny La cantidad de puntos en el array points_y + * @param closest_pair Las 2 pares de puntos mas cercano + * @return Retorna la distance entre los dos puntos mas cercano + */ +double divide_and_conquer_run(point_t *points_x, unsigned int nx, point_t *points_y, unsigned int ny, point_t *closest_pair) { + int left; + int right; + int i; + double mid; + double d = DBL_MAX; + double min_d = DBL_MAX; + double x0; + double x1; + double x; + point_t *closest_pair2; + point_t *points_y2; + if (nx <= 4) { + closest_pair2 = brute_force(points_x, nx, &d); + closest_pair[0] = closest_pair2[0]; + closest_pair[1] = closest_pair2[1]; + return d; + } + + closest_pair2 = malloc(sizeof(point_t) * 2); + points_y2 = malloc(sizeof(point_t) * ny); + mid = points_x[nx / 2].x; + + left = -1; + right = ny; + for (i = 0; i < ny; i++) { + if (points_y[i].x < mid) { + points_y2[++left] = points_y[i]; + } + else { + points_y2[--right]= points_y[i]; + } + } + + for (i = ny - 1; right < i; right ++, i--) { + closest_pair2[0] = points_y2[right]; + points_y2[right] = points_y2[i]; + points_y2[i] = closest_pair2[0]; + } + + min_d = divide_and_conquer_run(points_x, nx / 2, points_y2, left + 1, closest_pair); + d = divide_and_conquer_run(points_x + nx / 2, nx - nx / 2, points_y2 + left + 1, ny - left - 1, closest_pair2); + + if (d < min_d) { + min_d = d; + closest_pair[0] = closest_pair2[0]; + closest_pair[1] = closest_pair2[1]; + } + d = sqrt(min_d); + free(closest_pair2); + + left = -1; right = ny; + for (i = 0; i < ny; i++) { + x = points_y[i].x - mid; + if (x <= -d || x >= d) { + continue; + } + if (x < 0) { + points_y2[++left] = points_y[i]; + } + else { + points_y2[--right] = points_y[i]; + } + } + + while (left >= 0) { + x0 = points_y2[left].y + d; + + while (right < ny && points_y2[right].y > x0) { + right ++; + } + if (right >= ny) { + break; + } + + x1 = points_y2[left].y - d; + for (i = right; i < ny && points_y2[i].y > x1; i++) + if ((x = distance(points_y2[left], points_y2[i])) < min_d) { + min_d = x; + closest_pair[0] = points_y2[left]; + closest_pair[1] = points_y2[i]; + } + left--; + } + + free(points_y2); + return min_d; +} + /** * Encontrar los 2 puntos más cercano usando el metodo de dividir para conquistar - * @param point_ts Los puntos a calcular + * @param point_t Los puntos a calcular * @param n La cantidad de puntos en el array point_ts * @param minimum_dist La distancia minimo encontrado * @return Retorna los 2 puntos mas cercanos */ -int compareX(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a X - point_t *p1 = (point_t *)a, *p2 = (point_t *)b; - return (p1->x - p2->x); -} - -int compareY(const void* a, const void* b){ //ordena el arreglo de puntos de acuerdo a Y - point_t *p1 = (point_t *)a, *p2 = (point_t *)b; - return (p1->y - p2->y); -} - -double min(double x, double y){ // Función para encontrar el mayor entre dos valores flotantes - return (x < y)? x : y; -} - -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 -{ - double dist; - qsort(strip, n, sizeof(point_t), compareY); - - for (int i = 0; i < n; ++i) - for (int j = i+1; j < n && (strip[j].y - strip[i].y) < *minimum_dist; ++j) - if ((dist = distance(strip[i],strip[j])) < *minimum_dist){ - *minimum_dist = dist; - closest_pair[0] = strip[i]; - closest_pair[1] = strip[j]; - } -} - -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 - int mid = n/2; - point_t midpoint_t = P[mid]; - - // Consider the vertical line passing through the middle point_t - // calculate the smallest distance dl on left of middle point_t and - // dr on right side - double dl = closestUtil(P, mid, minimum_dist, closest_pair); - double dr = closestUtil(P + mid, n-mid, minimum_dist, closest_pair); - - double d = min(dl, dr); // Encontrar la distancia minima de dos puntos - - /* Crea un arreglo que contiene los puntos cercanos, mas cerca que d*/ - point_t strip[n]; - int j = 0; - for (int i = 0; i < n; i++) - if (abs(P[i].x - midpoint_t.x) < d) - strip[j] = P[i], j++; - - /*Encontrar el punto más cercano en la cinta, retornando el minimo de d y el más cercano - distance es strip[]*/ - *minimum_dist = min(d, stripClosest(strip, j, minimum_dist, closest_pair) ); - return *minimum_dist; -} - point_t * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) { point_t *closest_pair = malloc(sizeof(point_t) * 2); - qsort(points, n, sizeof(point_t), compareX); - closestUtil(points, n, minimum_dist, closest_pair); //Usa la funcion recursiva closestUtil para encontrar la distancia minima + point_t *points_x = malloc(sizeof(point_t) * n); + point_t *points_y = malloc(sizeof(point_t) * n); + memcpy(points_x, points, sizeof(point_t) * n); + memcpy(points_y, points, sizeof(point_t) * n); + qsort(points_x, n, sizeof(point_t), compare_x); + qsort(points_y, n, sizeof(point_t), compare_y); + *minimum_dist = divide_and_conquer_run(points_x, n, points_y, n, closest_pair); + free(points_x); + free(points_y); return closest_pair; } diff --git a/src/points.c b/src/points.c index dc9d897..3b79c85 100644 --- a/src/points.c +++ b/src/points.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "points.h" #include "distance.h" #include "timer.h" @@ -166,26 +167,18 @@ int main (int argc, char **argv) { end_algorithm(); fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); fprintf(stdout, "point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y); - fprintf(stdout, "distance: %lf\n\n", dist); + fprintf(stdout, "distance: %lf\n\n", sqrt(dist)); free(closest_points); closest_points = NULL; } if (divide) { - if (n <= 3) { - fprintf(stderr, "Divide and conquer necesita 4 o mas puntos!\nSe utilizará Brute Force como alternativa!\n"); - start_algorithm("Brute force corriendo... ", n); - closest_points = brute_force(points, n, &dist); - end_algorithm(); - } - else { - start_algorithm("Divide and conquer corriendo... ", n); - closest_points = divide_and_conquer(points, n, &dist); - end_algorithm(); - } + start_algorithm("Divide and conquer corriendo... ", n); + closest_points = divide_and_conquer(points, n, &dist); + end_algorithm(); fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y); fprintf(stdout, "point 2: x: %f y: %f\n", closest_points[1].x, closest_points[1].y); - fprintf(stdout, "distance: %lf\n", dist); + fprintf(stdout, "distance: %lf\n", sqrt(dist)); free(closest_points); closest_points = NULL; } diff --git a/test/test.c b/test/test.c index 8679b38..ff96157 100644 --- a/test/test.c +++ b/test/test.c @@ -30,7 +30,7 @@ * @param d2 El segudno double * @return Retorna 1 si son igual o 0 sino */ -int compare_double(double d1, double d2) { +inline int compare_double(double d1, double d2) { double precision = 0.000000001; if (((d1 - precision) < d2) && ((d1 + precision) > d2)) { return 1; @@ -72,7 +72,7 @@ int main(int argc, char **argv) { fprintf(stdout, "\tbrute force: "); fflush(stdout); brute_force(points, n, &dist); - if (compare_double(dist, 0.067687840)) { + if (compare_double(sqrt(dist), 0.067687840)) { fprintf(stdout, "passed\n"); passed++; } @@ -90,7 +90,7 @@ int main(int argc, char **argv) { fprintf(stdout, "\tdivide and conquer: "); fflush(stdout); divide_and_conquer(points, n, &dist); - if (compare_double(dist, 0.067687840)) { + if (compare_double(sqrt(dist), 0.067687840)) { fprintf(stdout, "passed\n"); passed++; }