平面最近点对问题,分治法,排序优化,归并排序,插入排序

    最近点对问题中涉及到对点按x或y进行升序排序,笔者尝试对排序方式进行优化。首先想到的自然是归并排序,毕竟归并排序的核心思想也是分治法,但是归并排序比较适合基数较多的情况。最后笔者更改思路如下:当点集合总数n的值小于50时,采用插入排序,当n的值大于50时采用归并排序,代码如下:

void MergeSort(point *a, int p, int r,bool sort_x_y)
{
	if ((r-p)>=50) // 小于50个数据的数组进行插入排序
	{
		int q = (p+r)/2;
		MergeSort(a, p, q,sort_x_y);
		MergeSort(a, q+1, r),sort_x_y;
		Merge(a, p, q, r,sort_x_y);
	}else
	{
		InsertionSort(a+p, r-p+1,sort_x_y);
	}
}
double ClosestPoint(point s_array[],int low,int high,point min_point[]){
    double d1,d2,d3,d;
    int mid,i,j,index;
    double x1,y1,x2,y2;         //记录点对的位置
    point P[high-low+1],temp1[2],temp2[2];         //辅助空间
    if(high-low==1){             //两个点的情况
        min_point[0].x=s_array[low].x;min_point[0].y=s_array[low].y;
        min_point[1].x=s_array[high].x;min_point[1].y=s_array[high].y;
        return Points_Distance(s_array[low],s_array[high]);
        }
    if(high-low==2){            //三个点的情况
        d1=Points_Distance(s_array[low],s_array[low+1]);
        d2=Points_Distance(s_array[low+1],s_array[high]);
        d3=Points_Distance(s_array[low],s_array[high]);
        if((d1<d2)&&(d1<d3)){
            min_point[0].x=s_array[low].x;min_point[0].y=s_array[low].y;
            min_point[1].x=s_array[low+1].x;min_point[1].y=s_array[low+1].y;
            return d1;
        }
        else if(d2<d3){
            min_point[0].x=s_array[low+1].x;min_point[0].y=s_array[low+1].y;
            min_point[1].x=s_array[high].x;min_point[1].y=s_array[high].y;
            return d2;
        }
        else {
            min_point[0].x=s_array[low].x;min_point[0].y=s_array[low].y;
            min_point[1].x=s_array[high].x;min_point[1].y=s_array[high].y;
            return d3;
        }
    }
    mid=(low+high)/2;       //其他情况递归
    d1=ClosestPoint(s_array,low,mid,min_point);
    temp1[0]=min_point[0];
    temp1[1]=min_point[1];
    d2=ClosestPoint(s_array,mid+1,high,min_point);
    temp2[0]=min_point[0];
    temp2[1]=min_point[1];
    if(d1<d2){
        d=d1;
        min_point[0]=temp1[0];
        min_point[1]=temp1[1];
    }
    else {
        d=d2;
        min_point[0]=temp2[0];
        min_point[1]=temp2[1];
    }
    index=0;
    for(i=mid;(i>=low)&&((s_array[mid].x-s_array[i].x)<d);i--)      //点集合p1
        P[index++]=s_array[i];
    for(i=mid+1;(i<=high)&&((s_array[i].x-s_array[mid].x)<d);i++)      //点集合p2
        P[index++]=s_array[i];
    MergeSort(P,P+index,Assist_y);                    //升序排列
    for(i=0;i<index;i++){
        for(j=j+1;j<index;i++){
            if((P[j].y-P[i].y)>=d)
                break;
            else {
                d3=Points_Distance(P[i],P[j]);
                if(d3<d){
                    min_point[0].x=P[i].x;min_point[0].y=P[i].y;
                    min_point[1].x=P[j].x;min_point[1].y=P[j].y;
                    d=d3;
                }
            }
        }
    }
    return d;
}
int main(){            //设定点的集合
    int n,dimension;
    double min_distance;
    cout<<"输入点的个数:\n";      //输入点的个数
    cin>>n;
    point s_array[n];
L1:    cout<<"请输入点所在的位面(一维输入1,二维输入2):";
	cin>>dimension;
	if(dimension==1) 
	    for(int i=0;i<n;i++)
	    {
	    	cout<<"请输入第"<<i+1<<"个点距离原点的距离"<<endl;
	        cin>>s_array[i].x;
	        s_array[i].y=0;
	    }
 	else if(dimension==2)
	    for(int i=0;i<n;i++)
	    {
	    	cout<<"请输入第"<<i+1<<"个点的坐标(用空格隔开)"<<endl;
	        cin>>s_array[i].x>>s_array[i].y;
	    }
  	else
  	{
  		cout<<"输入位面不合法"<<endl;
		  goto L1; 
  	}
    MergeSort(s_array,s_array+n,Assist_x);   
    point min_point[2];
    min_distance=ClosestPoint(s_array,0,n-1,min_point);
    cout<<"最小距离点对为:("<<min_point[0].x<<","<<min_point[0].y<<"),("<<min_point[1].x<<","<<min_point[1].y<<")";
    cout<<"最小距离为:\n"<<min_distance;      
    return 0;
}

    笔者没有给InsertionSort()和Merge()函数,因为这两个函数的代码量比预想中的大,按照x/y排序需要进行判断,需要要进行函数重载。在这里笔者给大家推荐sort()函数,只需用#include <algorithm> sort即可使用,它使用的排序方法是类似于快排的方法,时间复杂度为n*log2(n),执行效率较高。

    比如在上述笔者的代码中要实现只需要加两个函数如下:

bool Assist_y(point a,point b){          //按y升排序
    return a.y<b.y;
}
bool Assist_x(point a,point b){          //按x升排序
    return a.x<b.x;
}

    调用:

sort(s_array,s_array+n,Assist_x);//按x升序
sort(s_array,s_array+n,Assist_y);//按y升序

猜你喜欢

转载自blog.csdn.net/m0_37872090/article/details/80212670