implement divide and conquer
This commit is contained in:
parent
e37384d18f
commit
6ac113d408
@ -23,5 +23,5 @@
|
|||||||
* @return Retorna la distancia entre los 2 puntos
|
* @return Retorna la distancia entre los 2 puntos
|
||||||
*/
|
*/
|
||||||
double distance(point_t point1, point_t point2) {
|
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);
|
||||||
}
|
}
|
||||||
|
@ -14,74 +14,167 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <float.h>
|
||||||
#include "points.h"
|
#include "points.h"
|
||||||
#include "brute_force.h"
|
#include "brute_force.h"
|
||||||
#include "distance.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
|
* 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 n La cantidad de puntos en el array point_ts
|
||||||
* @param minimum_dist La distancia minimo encontrado
|
* @param minimum_dist La distancia minimo encontrado
|
||||||
* @return Retorna los 2 puntos mas cercanos
|
* @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 * divide_and_conquer(point_t *points, unsigned int n, double *minimum_dist) {
|
||||||
point_t *closest_pair = malloc(sizeof(point_t) * 2);
|
point_t *closest_pair = malloc(sizeof(point_t) * 2);
|
||||||
qsort(points, n, sizeof(point_t), compareX);
|
point_t *points_x = malloc(sizeof(point_t) * n);
|
||||||
closestUtil(points, n, minimum_dist, closest_pair); //Usa la funcion recursiva closestUtil para encontrar la distancia minima
|
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;
|
return closest_pair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
src/points.c
13
src/points.c
@ -18,6 +18,7 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <math.h>
|
||||||
#include "points.h"
|
#include "points.h"
|
||||||
#include "distance.h"
|
#include "distance.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
@ -166,26 +167,18 @@ int main (int argc, char **argv) {
|
|||||||
end_algorithm();
|
end_algorithm();
|
||||||
fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y);
|
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, "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);
|
free(closest_points);
|
||||||
closest_points = NULL;
|
closest_points = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (divide) {
|
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);
|
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();
|
end_algorithm();
|
||||||
}
|
|
||||||
fprintf(stdout, "point 1: x: %f y: %f\n", closest_points[0].x, closest_points[0].y);
|
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, "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);
|
free(closest_points);
|
||||||
closest_points = NULL;
|
closest_points = NULL;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
* @param d2 El segudno double
|
* @param d2 El segudno double
|
||||||
* @return Retorna 1 si son igual o 0 sino
|
* @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;
|
double precision = 0.000000001;
|
||||||
if (((d1 - precision) < d2) && ((d1 + precision) > d2)) {
|
if (((d1 - precision) < d2) && ((d1 + precision) > d2)) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -72,7 +72,7 @@ int main(int argc, char **argv) {
|
|||||||
fprintf(stdout, "\tbrute force: ");
|
fprintf(stdout, "\tbrute force: ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
brute_force(points, n, &dist);
|
brute_force(points, n, &dist);
|
||||||
if (compare_double(dist, 0.067687840)) {
|
if (compare_double(sqrt(dist), 0.067687840)) {
|
||||||
fprintf(stdout, "passed\n");
|
fprintf(stdout, "passed\n");
|
||||||
passed++;
|
passed++;
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ int main(int argc, char **argv) {
|
|||||||
fprintf(stdout, "\tdivide and conquer: ");
|
fprintf(stdout, "\tdivide and conquer: ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
divide_and_conquer(points, n, &dist);
|
divide_and_conquer(points, n, &dist);
|
||||||
if (compare_double(dist, 0.067687840)) {
|
if (compare_double(sqrt(dist), 0.067687840)) {
|
||||||
fprintf(stdout, "passed\n");
|
fprintf(stdout, "passed\n");
|
||||||
passed++;
|
passed++;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user