最近点对问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法分析与设计最近对问题
最近对问题
问题描述:
在二维平面上的n 个点中,如何快速的找出最近的一对点,就是最近点对问题。 程序设计思想:
1.蛮力法求最近对问题:
基本思想:
分别计算每一对点之间的距离,然后找出距离最小的那一对,为了避免对同一对点计
算两次距离,只考虑j i <的那些点对()
j i P P ,。
复杂度分析:
对于此算法,主要就是算两个点的欧几里得距离。注意到在求欧几里得距离时,避免了求平方根操作,其原因是:如果被开方的数越小,则它的平方根也越小。所以复杂度就是求平方,求执行次数为: )()1()(2n O n n n T =-=;即时间复杂度为)(2n O 。
2.分治法求最近对问题:
基本思想:
用分治法解决最近点对问题,就是将一个问题分解两个子问题,然后递归处理子问题,然后合并。可能两个点在每个子问题中,也可能两个点分别在两个子问题中,就这两种情况。则基本过程为:找一条中垂线m (坐位S 集合x 坐标的中位数)把n 个元素分成左右两部分元素,然后分别求得两边的最短距离1d ,2d ,然后取两者中的最小者记为d ,在中线两边分别取d 的距离,记录该距离范围内点的个数,中线左边有L 个元素,右边有R 个元素,分别将两边的点按y 坐标升序排列,在左边集合中每一个点,找右边集合的点,找到与之距离小于d 的点,更新最短距离,直到循环结束,即可求出最短距离。 复杂度分析:
应用分治法求解含有n 个点的最近对问题,其时间复杂性可由递推式表示:)()2/(*2)(n f n T n T +=。
由以上分析:合并子问题的解的时间)1()(O n f =。进而可得分治法求最近对问题的时间复杂度为:)log ()(2n n O n T =。
程序代码:
#include
#include
#include
#define NUM 1000
typedef struct{
int x;
int y;
}N;
double distance(N n1,N n2);
double minDis(double d1,double d2);
double shortestDis(N *data,int length,N *n1 , N *n2); double shortestDis(N *data,int length,N *n1 , N *n2){ int pre,last,middle,median;
int i,c1num = 0,c2num = 0,j;
N* dataP;
N* dataL;
N* CP;
N* CL;
N tn1,tn2;
double dis1 ,dis2;
// 当只有两个点时,返回最短距离,和点
if(length == 2 ){
double dis1 = distance(data[0],data[1]);
*n1 = data[0];
*n2 = data[1];
return dis1;
}else if(length == 3){
// 当只有三个点时,返回最短距离,和点
double dis1 = distance(data[0],data[1]);
double dis2 = distance(data[1],data[2]);
double dis3 = distance(data[0],data[2]);
double temp;
temp = dis1 < dis2 ? dis1:dis2;
temp = temp < dis3 ? temp : dis3;
if(temp == dis1){
*n1 = data[0];*n2 = data[1];
}else if(temp == dis2){
*n1 = data[1];*n2 = data[2];
}else{
*n1 = data[0];*n2 = data[2];
}
return temp;
}
middle =length/2;
pre = middle;
last = length - pre;
median = data[middle].x; // 记录中位数
dataP = (N*)malloc(sizeof(N)*pre);
dataL = (N*)malloc(sizeof(N)*last);
CP = (N*)malloc(sizeof(N)*pre);
CL = (N*)malloc(sizeof(N)*last);
for( i = 0;i < pre ;i++)
dataP[i] = data[i];
for( i = 0; i< last;i++)
dataL[i] = data[i+pre];
dis1 = shortestDis(dataP , pre , n1 , n2);
dis2 = shortestDis(dataL , last , &tn1 , &tn2);
if(dis1 > dis2){
*n1 = tn1;
*n2 = tn2;
}
dis1 = minDis(dis1,dis2);
for( i = 0; i < pre ; i++)
if(dataP[i].x - median < dis1){
CP[c1num++] = dataP[i];
} // 将在中位数之前的区域中与中位数距离小于最短距离的点放到CP 中
for( i = 0; i < last ; i++)
if(median - dataL[i].x < dis1){
CL[c2num++] = dataL[i];
}// 将在中位数之后的区域中与中位数距离小于最短距离的点放到CL 中
for(i = 0; i< c1num;i++){
for( j =0; j < c2num ; j++){
double temp = distance(CP[i],CL[j]);
if(temp < dis1){
dis1 = temp;
*n1 = CP[i];
*n2 = CL[j];
}
}
}//依次计算中位数两旁的区域中,每一个点与另外一个区域中的距离,并且记录最短距离
return dis1;
}
double distance(N n1,N n2){
return sqrt((n1.x -n2.x)*(n1.x -n2.x) + (n1.y - n2.y)*(n1.y - n2.y));
}
double minDis(double d1,double d2){
double d = d1 < d2 ? d1 : d2;
return d;
}
// 分治法排序
void MergeSort(N q[],int num,int mode){