最近点对问题中涉及到对点按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升序