1. 问题
前提:令P为笛卡儿平面上n>1个点构成的集合。简单起见,假设集合中的每个点都不一-样。
我们还假设这些点是按照其x轴坐标升序排列的。(如果不是这样,可以事先用类似合并排序这样的高效算法对其排序。)为了更加方便,我们还可以按照点的y轴坐标在另一个列表中进行升序排列,并将这个列表示为Q。
当2≤n≤3时,问题就可以通过蛮力算法求解。
当n>3时,可以利用点集在x轴方向上的中位数m,在该处作一条垂线, 将点集分成大小分别为 「n/2]和[n/2」的两个子集P和Pro即使得其中「n/27个点位于线的左边或线上,[n/2 ]个点位于线的右边或线上。然后就可以通过递归求解子问题P和P来得到最近点对问题的解。其中d,和d,分别表示在P和P中的最近对距离,并定义d = min{d,d}。
问题:最近对问题要求在包含有n个点的集合S中,找出距离最近的两个点。设 p1(x1,y1),p2(x2,y2),……,pn(xn,yn)是平面的n个点。
严格地说,最近点对可能不止一对,此例输出一对即可。
2. 解析
3. 设计
//实现求最近对距离
double Closest(point S[], int low, int high){
double d1, d2, d3, d;
int mid, i, j, index;
point P[n]; //存放点集合 P1和P2
//如果只有两个点,返回这两个点间的距离
if (high - low == 1) {
return Distance(S[low], S[high]);
}
if (high - low == 2) {//如果有三个点,求最近点对距离
d1 = Distance(S[low], S[low + 1]);
d2 = Distance(S[low + 1], S[high]);
d3 = Distance(S[low], S[high]);
if ((d1 < d2) && (d1 < d3)) return d1;
else if (d2 < d3) return d2;
else return d3;
}
mid = (low + high) / 2; //计算中间点
d1 = Closest(S, low, mid); //递归求解子问题①
d2 = Closest(S, mid + 1, high); //递归求解子问题②
if (d1 <= d2) d = d1; //已下为求解子问题
else d = d2;
index = 0;
for (i = mid; (i >= low) && (S[mid].x - S[i].x < d); i--) //建立点集合P1
P[index++] = S[i];
for (i = mid + 1; (i <= high) && (S[i].x - S[mid].x < d); i++) //建立点集合P2
P[index++] = S[i];
QuickSort(P, 0, index - 1);//对集合P1、P2按y坐标升
//依次处理集合P1和P2中的点
for (i = 0; i < index; i++) {
for (j = i + 1; j < index; j++) {
if (P[j].y - P[i].y >= d) //超出y坐标的范围,点P[i]处理完毕
break;
else {
d3 = Distance(P[i], P[j]);
if (d3 < d)
d = d3;
}
}
}
return d;
}
//求两点之间距离
double Distance(point a, point b){
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
4. 分析
时间复杂度:O(nlog2n)
5. 源码
https://github.com/moshang1113/Clostest-Pair