zoukankan      html  css  js  c++  java
  • 二维空间下的最近点对查找

    // 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坐标交替输入)

  • 相关阅读:
    第二阶段站立会议05
    第二阶段站立会议04
    第一阶段冲刺总结
    站立会议08
    站立会议07
    站立会议06
    站立会议05
    站立会议04
    第一次冲刺第3天
    站立会议2
  • 原文地址:https://www.cnblogs.com/sunshinewill/p/2943714.html
Copyright © 2011-2022 走看看