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 <graphics.h> #include <stdio.h> #include <math.h> #include <time.h> #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) { 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; 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; } } 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; }