二维空间下的最近点对查找

// space_minum.cpp : Defines the entry point for the console application.
//
#include <iostream>
#include <math.h>

using namespace std;

float minu=10000000;
int fff,bbb;

void Insertsort(float list[],float X[],int a,int b);
void Insertsort(float list[],float X[],int a,int b){
	float next,tmp;//插入排序,对xy坐标组按照x坐标排序
	int j;
	if(a>b)return;
	for(int x=a;x<=b;x++){
	next=list[x];
	tmp=X[x];
	for(j=x-1;j>=a&&next<list[j];j--)
	{list[j+1]=list[j];
	X[j+1]=X[j];
	}
	list[j+1]=next;
	X[j+1]=tmp;
	}

}

float Dis(float x1,float y1,float x2,float y2){
float ans=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
return ans;
}

int find_tmp(int mid,int limit,float dis,char updown,float x[]){
	int i=mid;
if(updown=='f'){//向前搜索
	for(i;i>=limit&&x[mid]-dis<x[i];i--);
return i;
}
else if(updown=='b'){//向后搜索
	for(i;i<=limit&&x[mid]+dis>x[i];i++);
return i;
}

}




float seperate(float x[],float y[],int left,int right){
int mid=(left+right)/2;
float dis=minu;

if(right-left==0)return dis;
else if(right-left==1) {
	float t=Dis(x[right],y[right],x[left],y[left]);
		if(t<minu){minu=t;fff=right;bbb=left;}
	return t;
}
else {
	float ll=seperate(x,y,left,mid);
	float rr=seperate(x,y,mid,right);
	if(ll<rr)dis=ll;else dis=rr;
	if(minu<dis)dis=minu;//修改为在以计算过的点中最小值,而非该划分中的最小值,提高速度
	
	float t_mid=x[mid];//从划分元拓展dis单位
	int f,b;
	f=find_tmp(mid,left,dis,'f',x);//向前向后搜索查找范围内元素
	b=find_tmp(mid,right,dis,'b',x);


	//从mid-f个点依次选出点与b-mid个点计算最小值
//注:已经按照x坐标进行排序,当x[b]-x[f]中点>=dis时,f++,b从mid重新开始

float tmp=0;
for(int i=f;i<mid;i++){
	for(int j=mid;j<=b;j++){//修改比较条件j<=b&&j-mid<=6,原因已在文档中说明
	if(x[j]-x[i]<dis)
		tmp =Dis(x[i],y[i],x[j],y[j]);
	else break;
	if(tmp!=0&&tmp<dis){dis=tmp;minu=tmp;
	//cout<<i<<' '<<fff<<' ';
	fff=i;bbb=j;
	}
	}
}

return dis;


//	float t=0;for(int i=f;i<=mid;i++){for(int j=mid;j<=b;j++){
//	t =Dis(x[i],y[i],x[j],y[j]);if(t!=0&&t<dis)dis=t;}}return dis;

}
}




const int	max=20;
int main(int argc, char* argv[])
{

float x[max];
float y[max];
cout<<"输入点对数";
int n;
cin>>n;
cout<<"输入图中点坐标x,y"<<endl;
for(int i=0;i<n;i++)
cin>>x[i]>>y[i];
//for(i=0;i<n;i++)
//cout<<x[i]<<' '<<y[i];
//按照x坐标排序,用于划分
Insertsort(x,y,0,n-1);
//for(i=0;i<n;i++)
//cout<<x[i]<<' '<<y[i]<<'|';cout<<endl;

cout<<seperate(x,y,0,n-1)<<endl;
cout<<'['<<x[fff]<<','<<y[fff]<<']'<<endl;
cout<<'['<<x[bbb]<<','<<y[bbb]<<']'<<endl;
	return 0;
}

算法思想与分析

通过递归划分子空间,减小问题规模。

当子问题中点数为0返回极大值;点数为1时,返回与划分点之间的距离。

         在将N个点进行空间划分前,先按照x坐标进行排序,后依据x坐标采用二分法来进行划分。计算空间距离伪代码如下:

         Separate(x[],y[],left,right){

         if(right-left=0)return dis;//默认为一极大值

         else if(right-left=1)return Dis(x[]y[],right,left)

//right,left为下标,同一个点在xy数组上下标一致

          else {

                   ll= Separate(x[],y[],left,mid)

                   rr= Separate(x[],y[],mid,right)

                   dis=min(ll,rr);//记录最小值

                   f=find_pos(mid,left,dis,x)

//对以按x坐标排好序的点,从中间往左寻找在dis范围内点,返回值为下标

                  b= find_pos(mid,right,dis,x)

//对以按x坐标排好序的点,从中间往右寻找在dis范围内点,返回值为下标

//在f-mid中按照x递增顺序选择一个点A,找mid-b范围内按x递增的一点B

//保证AB两点x坐标之差小于等于dis,计算在范围内符合约束条件的点对的最小值

                   for(int i=f;i<mid;i++)

                            for(int j=mid;j<=f;j++)//可以只访问排序后右侧前6个点j<=f&&j-mid<=6

                                     {if(x[j]-x[i]<dis)

                                      tmp =Dis(x[],y[],I,j)

                                     else break//不符合跳出、再从f-mid范围内选择一点

if(tmp<dis)dis=tmp//修改最小值

}

}

return dis

}

 

算法复杂度分析

因为该算法采用分治法,将问题分解为两个子问题,合并的复杂度为O(n),所以时间复杂度为:T(n)=2*T(n/2)+n

通过推倒得到算法复杂度为O(n*logn)

在算法开始前对数据有按照x轴坐标排序,采用复杂度为O(n*logn)的算法,得到最终算法复杂度为O(n*logn)。

其中,在合并过程中,因为在选择范围时以左右最小值dis选取范围,则在左侧区域选择的点,在包括中轴在内的右侧区域中选一点,保证点之间距离为dis则最多存在6个点,否则dis可进一步缩小。

如下图展示说明,鸽巢原理:

实验结果

实验数据:[2,2][1.5,1.5][3.5,1][1.75,1.25]为例:(输入数据xy坐标交替输入)

转载于:https://www.cnblogs.com/sunshinewill/archive/2013/03/05/2943714.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值