私はdivide and conquerアプローチを使用して最も近い点のペアを見つける方法を実装しようとしています。最も近い点のペアを見つける - 再帰的なサイドペアの関数呼び出しの中でスプリットペアを実装する方法
まず、スプリットペア(p1、p2)は、p1が左側、右側がp2となるように最も近いペアです。サイドペア(p3、p4)は、p3とp4が一方の側にあるような最も近いペアです。
closest_split_pairs
関数が別途呼び出された場合(関数closest_side_pairs
ではなく)、正しい結果を返す実装を行っています。私はこれらの点を提供あれば:
2,1
8,3
5,8
9,1
5,2
3,3
4,5
6,5
1,9
2,1.5
を私は2,1
と2,1.5
の結果を取得します。 (私はそれがそのようであるべきだと思う)
しかし、私はclosest_side_pairs
内closest_split_pair
を呼び出した場合..私は間違った結果3,3
と4,5
を取得します。問題は、closest_split_pairs
をclosest_side_pairs
の中に組み込むために何をしなければならないのか分かりません。コードclosest_split_pairs
はclosest_side_pairs
と呼ばれ、別の呼び出しはmain
機能でコメントされています。
#include <iostream>
#include <array>
#include <algorithm>
#include <fstream>
#include <cfloat>
#include <cmath>
struct Point {
Point(double x = 0, double y = 0) {
x_coordinate = x;
y_coordinate = y;
}
double x_coordinate;
double y_coordinate;
static bool sortByX(const Point &lhs, const Point &rhs) {
return lhs.x_coordinate < rhs.x_coordinate;
}
static bool sortByY(const Point &lhs, const Point &rhs) {
return lhs.y_coordinate < rhs.y_coordinate;
}
};
using p_iterator = std::vector<Point>::iterator;
template<std::size_t SIZE>
using p_iterators_array = std::array<std::vector<Point>::iterator, SIZE>;
void initialize_points(std::vector<Point> &points) {
double x, y;
char c;
std::ifstream infile("./points.txt");
while((infile >> x >> c >> y) && (c == ',')) {
points.push_back(Point(x, y));
}
}
double calculate_distance(Point &p1, Point &p2) {
return std::sqrt(std::pow(p1.x_coordinate - p2.x_coordinate, 2) + std::pow(p1.y_coordinate - p2.y_coordinate , 2));
}
template<typename T>
p_iterators_array<2> eucledian_closest(T &points, int size) {
p_iterators_array<2> closest_arr;
double closest_distance = DBL_MAX, distance = 0.0;
for(int i = 0; i < size - 1; i++){
for(int j = i + 1; j < size; j++) {
distance = calculate_distance(points[i], points[j]);
if(distance < closest_distance) {
closest_distance = distance;
closest_arr[0] = points + i;
closest_arr[1] = points + j;
}
}
}
return closest_arr;
}
p_iterators_array<2> closest_split_pair(p_iterator points_iterator, p_iterators_array<2> &closest_side_pairs, std::size_t size) {
std::vector<p_iterator> split_pairs;
p_iterators_array<2> final_result;
double closest_distance = DBL_MAX, distance = 0.0;
p_iterator midpoint = points_iterator + (size/2);
//filtering points to only points in sigma-2sigma rectangle
for (size_t i = 0; i < size; i++) {
if(std::abs(points_iterator[i].x_coordinate - midpoint->x_coordinate) < calculate_distance(*(closest_side_pairs[0]), *(closest_side_pairs[1]))){
split_pairs.push_back(points_iterator + i);
}
}
//finding closest pair in split_pairs
for (size_t i = 0; i < split_pairs.size() - 1; i++) {
for (size_t j = i+1; (j < 7) && (j < split_pairs.size()) ; j++) {
distance = calculate_distance(*(split_pairs[i]), *(split_pairs[j]));
if(distance < closest_distance) {
closest_distance = distance;
final_result[0] = split_pairs[i];
final_result[1] = split_pairs[j];
}
}
}
//comparing split paris distance and side pairs distance
if(calculate_distance(*(closest_side_pairs.front()), *(closest_side_pairs.back())) < calculate_distance(*(final_result.front()), *(final_result.back()))) {
final_result = closest_side_pairs;
}
return final_result;
}
p_iterators_array<2> closest_side_pair(p_iterator points_iterator, p_iterator x_arr_iterator, p_iterator y_arr_iterator, std::size_t size) {
std::size_t delimeter = size/2 ;
if(delimeter <= 3) {
return eucledian_closest(points_iterator, delimeter);
}
p_iterators_array<2> closest_left, closest_right, result;
closest_left = closest_side_pair(points_iterator, x_arr_iterator, y_arr_iterator, delimeter);
closest_right = closest_side_pair(points_iterator + delimeter, x_arr_iterator + delimeter, y_arr_iterator + delimeter, delimeter);
if(calculate_distance(*(closest_left.front()), *(closest_left.back())) < calculate_distance(*(closest_right.front()), *(closest_right.back()))) {
result = closest_left;
} else {
result = closest_right;
}
return closest_split_pair(points_iterator, result, delimeter);
}
int main()
{
std::vector<Point> points;
initialize_points(points);
std::vector<Point> x_p = points;
std::vector<Point> y_p = points;
std::sort(x_p.begin(), x_p.end(), Point::sortByX);
std::sort(y_p.begin(), y_p.end(), Point::sortByY);
p_iterators_array<2> closest_result = closest_side_pair(points.begin(), x_p.begin(), y_p.begin(), points.size());
//Separate call of closest_split_pair
//closest_result = closest_split_pair(points.begin(), closest_result, points.size());
std::cout << "Closest pair are: " << std::endl;
for(auto p: closest_result) {
std::cout << p->x_coordinate << ", " << p->y_coordinate << std::endl;
}
}
これは、https://en.wikipedia.org/wiki/Closest_pair_of_points_problemの再帰分割と征服のアルゴリズムとは一致していません。これらのアルゴリズムは軸を1つ選択し、両方を実行しようとしていますが、ソートされていない元のデータセット?また、奇数の要素がある場合、配列を正しく分割するかどうかはわかりません。 –