1.按x对点对数组进行从小到大排序
2.找出x中间值,按中间值划分数组为左右两部分
3.不断细分,找出左右两部分的最近点对
4.重复步骤1.2.3,得到最终左右两部分的最近点对的距离d
5.找出 |X - Xmid| < d ,部分的点对,此部分左边的点对集合我们设为p1,右边设为p2,对p1,p2中的点按y的大小从小到大排序
6.对P1中所有点p,对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者,对P1中每一点最多只要检查P2中排好序的相继6个点,具体证明见:这位仁兄的帖子
#ifndef _CLOSESTPAIR_H_
#define _CLOSESTPAIR_H_
typedef struct Point
{
int x;
int y;
}Point;
void setPoints(Point points[], int pointsLength);
int Distance(Point point1, Point point2);
void sort(Point points[], int s, int e, char z);
void merge(Point points[], int s, int e, int mid, char z);
void divideByMid(int mid, Point points[], Point pointsL[], Point pointsR[], int n);
int getClosestInSides(Point points[], int pointsLength);
int getClosest(Point points[], Point result[2], int pointsLength);
#endif
#include "ClosestPair.h"
#include
#include
#include
#include
#define LENGTH 100
#define MYINFINITE 100000;
int main()
{
initgraph(960, 540);
setcolor(WHITE);
Point points[LENGTH] = { 0,0 };
Point result[2] = { 0,0 };
int distance = 0;
setPoints(points, LENGTH);
for (int i = 0; i < LENGTH; i++)
{
circle(points[i].x, points[i].y, 1);
}
distance = getClosest(points, result, LENGTH);
setlinecolor(GREEN);
line((int)result[0].x, (int)result[0].y, (int)result[1].x, (int)result[1].y);
setcolor(RED);
circle((int)result[0].x, (int)result[0].y, 1);
circle((int)result[1].x, (int)result[1].y, 1);
outtextxy(5, 5, "distance: ");
char distanceText[20];
_itoa_s(distance, distanceText, 10);
outtextxy(70, 5, distanceText);
system("pause");
getchar();
return 0;
}
//在画面生成内不重复的一定数量的点
void setPoints(Point points[],int pointsLength)
{
srand((unsigned)time(0));
for (int i = 0; i < pointsLength; i++)
{
points[i].x = rand() % 960;
points[i].y = rand() % 540;
for (int j = 0; j < i; j++)
{
if (points[j].x == points[i].x && points[j].y == points[j].x)
{
i--;
}
}
}
return;
}
//获得两点距离
int Distance(Point point1, Point point2)
{
int distance = sqrt(pow(point1.x - point2.x, 2) + pow(point1.y - point2.y, 2));
return distance;
}
//归并排序
void sort(Point points[], int s, int e,char z)
{
if (s < e)
{
int mid = (s + e) / 2;
sort(points, s, mid, z);
sort(points, mid + 1, e, z);
merge(points, s, e, mid, z);
return;
}
}
//归并
void merge(Point points[], int s, int e, int mid, char z)
{
int length1 = mid - s + 1;
int length2 = e - mid;
Point *AL = (Point*)malloc(sizeof(Point)*length1);
Point *AR = (Point*)malloc(sizeof(Point)*length2);
int i = 0, j = 0, k = s;
for (i = s; i <= mid; i++)
{
AL[i - s] = points[i];
}
for (j = mid + 1; j <= e; j++)
{
AR[j - mid - 1] = points[j];
}
switch (z)
{
//对横坐标x进行排序
case 'x':
i = 0; j = 0;
while (i < length1&&j < length2)
{
if (AL[i].x < AR[j].x)
{
points[k++] = AL[i++];
}
else points[k++] = AR[j++];
}
while (i < length1)
{
points[k++] = AL[i++];
}
while (j < length2)
{
points[k++] = AR[j++];
}
break;
//对纵坐标y进行排序
case 'y':
i = 0; j = 0;
while (i < length1&&j < length2)
{
if (AL[i].y < AR[j].y)
{
points[k++] = AL[i++];
}
else points[k++] = AR[j++];
}
while (i < length1)
{
points[k++] = AL[i++];
}
while (j < length2)
{
points[k++] = AR[j++];
}
break;
default:
free(AL);
free(AR);
break;
}
return;
}
//按中心划分左右两部分点对
void divideByMid(int mid, Point points[], Point pointsL[], Point pointsR[], int n)
{
int i = 0, j = 0, k = 0;
for (i = 0; i < n; i++)
{
if (points[i].x > mid)
{
pointsR[j++] = points[i];
}
else {
pointsL[k++] = points[i];
}
}
return;
}
//在左右点集中获得最近点对
int getClosestInSides(Point points[], int pointsLength)
{
int distance;
if (pointsLength < 2)
{
distance = MYINFINITE;
}
else if (pointsLength == 2)
{
distance = Distance(points[0], points[1]);
}
else
{
Point * pointsL = (Point*)malloc(sizeof(Point)*(pointsLength));
Point * pointsR = (Point*)malloc(sizeof(Point)*(pointsLength));
//初始化数组中各点坐标
for (int i = 0; i < pointsLength; i++)
{
if (i < pointsLength / 2)
{
pointsL[i].x = 0;
pointsL[i].y = 0;
}
else
{
pointsR[i - pointsLength / 2].x = 0;
pointsR[i - pointsLength / 2].y = 0;
}
}
//按x排序
sort(points, 0, pointsLength - 1, 'x');
//分治
divideByMid(points[pointsLength/2].x, points, pointsL, pointsR,pointsLength);
//分治后求解
int distance_L = getClosestInSides(pointsL, pointsLength / 2);
int distance_R = getClosestInSides(pointsR, pointsLength - pointsLength / 2);
if (distance_L > distance_R)
{
distance = distance_L;
}
else distance = distance_R;
free(pointsR);
free(pointsL);
}
return distance;
}
//获取全局最近点对
int getClosest(Point points[], Point result[2], int pointsLength)
{
int distance = getClosestInSides(points, pointsLength);
sort(points, 0, pointsLength - 1, 'y');
Point * pointsCenter = (Point *)malloc(sizeof(Point)*pointsLength);
int pointsCenterLength = -1;
for (int i = 0; i < pointsLength; i++)
{
if (fabs(points[i].x - points[pointsLength/2].x) < distance)
{
pointsCenter[++pointsCenterLength] = points[i];
}
}
for (int i = 0; i < pointsCenterLength; i++)
{
for (int j = i + 1; j <= i + 7 && j < pointsCenterLength; j++)
{
if (Distance(pointsCenter[i], pointsCenter[j]) < distance)
{
distance = Distance(pointsCenter[i], pointsCenter[j]);
result[0] = pointsCenter[i];
result[1] = pointsCenter[j];
}
}
}
free(pointsCenter);
return distance;
}