算法实验四_空间最近点对算法
最接近点对问题实验报告

最接近点对问题一.实验目的:1.理解算法设计的基本步骤及各步的主要内容、基本要求;2.加深对分治设计方法基本思想的理解,并利用其解决现实生活中的问题;3.通过本次实验初步掌握将算法转化为计算机上机程序的方法。
二.实验内容:1.编写实现算法:给定n对点,在这n对点中找到距离最短的点对。
2.将输出数据存放到另一个文本文件中,包括结果和具体的运行时间。
3.对实验结果进行分析。
三.实验操作:1.最接近点对查找的思想:首先,将所有的点对按照x坐标排序,找到x坐标的中位数,将所有的点对分成三部分,横坐标小于x(S1)、等于x(S2)和大于x(S3)的点对,在求取每部分中的最短距离,利用分治法,一步步地分解为子问题,找到最短距离d。
由于距离最近的两个点可能在不同的区域中,需要进一步判断。
选择S1中的一个点,由于与它相比较的点的距离不可能超过d,故其配对范围为d*2d的矩形,将这个矩形划分为6份2/d*3/d的小矩形,其对角线的长度为5/6d,小于d,故S1中的任意一个点只需和S2中的6个点比较即可,最终确定最短的距离。
2.取中位数:为了减少算法的时间开销,需要将所有的点对进行分组,以中位数为基准,考虑到快速排序的不稳定性,本次排序使用了合并排序。
代码实现:template <class Type>void Merge(Type c[],Type d[],int l,int m,int r){int i = l,j = m + 1,k = l;while((i<=m)&&(j<=r)){if(c[i]<=c[j]) d[k++] = c[i++];else d[k++] = c[j++];}if(i>m) {for(int q=j; q<=r; q++) d[k++] = c[q];}else{for(int q=i; q<=m; q++) d[k++] = c[q];}}template <class Type>void MergeSort(Type a[],Type b[],int left,int right){if(left<right){int i = (left + right)/2;MergeSort(a,b,left,i);MergeSort(a,b,i+1,right);Merge(a,b,left,i,right);//合并到数组aCopy(a,b,left,right);//复制回数组a}}3.数据存入文件:本次对文件的输入没有存入文本文件中,只将输出数据输入到指定的文件夹中,用到了输出流文件。
最近点对问题

最近点对问题I.一维问题:一、问题描述和分析最近点对问题的提法是:给定平面上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。
严格的讲,最接近点对可能多于1对,为简单起见,只找其中的1对作为问题的解。
简单的说,只要将每一点与其它n-1个点的距离算出,找出达到最小距离的2点即可。
但这样效率太低,故想到分治法来解决这个问题。
也就是说,将所给的平面上n个点的集合S 分成2个子集S1和S2,每个子集中约有n/2个点。
然后在每个子集中递归的求其最接近的点对。
这里,关键问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。
如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决,但如果这2个点分别在S1和S2中,问题就不那么简单了。
下面的基本算法中,将对其作具体分析。
二、基本算法假设用x轴上某个点m将S划分为2个集合S1和S2,使得S1={x∈S|x<=m};S2={x ∈S|x>m}。
因此,对于所有p∈S1和q∈S2有p<q。
递归的在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设d=min{|p1-p2|,|q1-q2|}。
由此易知,S中的最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{p3,q3},其中p3∈S1且q3∈S2。
如下图所示:S1 S2p1 p2 p3 q1 q2 q3图1 一维情形的分治法注意到,如果S的最接近点对是{p3,q3},即|p3-q3|<d,则p3和q3两者与m的距离不超过d,即|p3-m|<d,|q3-m|<d。
也就是说,p3∈(m-d,m],q3∈(m,m+d]。
由于每个长度为d的半闭区间至多包含S1中的一个点,并且m是S1和S2的分割点,因此(m-d,m]中至少包含一个S中的点。
同理,(m,m+d]中也至少包含一个S中的点。
数据结构与算法之最近点对

思路:结合分治法 首先将输入的坐标组按x轴值用快接读出的x轴中值m 将坐标数组分为两部分 分别处理两个子段 两子部分返回最小的两点长度leng1,leng2 得到暂时最小的两点长度leng,为MIN(leng1,leng2) 这是两个两点p、q在同一个子集情况
然后就是求两个点p、q不在同一个子集的情况 使用两个游标i、j从m和m+1遍历两个子段 由于两个子集也为有序的 若两点横轴距离大于leng或者讨论满足横轴距离 和纵轴距离都小于leng的达到6个,可以跳出内 层遍历循环
leng1=maxLength(a,low,m); leng2=maxLength(a,m+1,high); leng=leng1<leng2?leng1:leng2; for (i=m;i>low-1;i--) for (num=6,j=m+1;j<high+1;j++) { if (a[j][1]-a[i][1]>leng) continue; if (a[j][0]-a[i][0]>leng || num==0) break; x=a[j][0]-a[i][0]; y=a[j][1]-a[i][1]; z=sqrt(x*x+y*y); num--; if (z<leng) leng=z; }
最近点对算法

最近点对算法1. 简介最近点对算法(Closest Pair Algorithm)是一种用于找到平面上最近的两个点的算法。
该算法可以在给定一组点的情况下,找到距离最近的两个点,并计算出它们之间的距离。
最近点对问题在计算几何学、图像处理、数据挖掘等领域中具有广泛应用。
例如,在地理信息系统中,可以使用最近点对算法来查找距离最近的两个地理位置;在机器视觉中,可以使用该算法来寻找图像中距离最接近的两个特征点。
2. 算法思想最近点对算法采用分治策略,将问题划分为多个子问题,并通过递归求解子问题来得到整体解。
其基本思想可以概括为以下步骤:1.将所有点按照横坐标进行排序。
2.将排序后的点集平均划分为左右两部分,分别称为P_left和P_right。
3.分别在P_left和P_right中递归求解最近点对。
4.在左右两部分求得的最近点对中,选择距离更小的那一对作为候选解。
5.在区间[P_left[-1].x, P_right[0].x]内,查找可能的更近点对。
6.比较候选解与新找到的更近点对,选择距离更小的那一对作为最终解。
3. 算法实现3.1 数据结构在实现最近点对算法时,需要定义合适的数据结构来表示点。
常见的表示方法是使用二维数组或类对象。
以下是使用类对象来表示点的示例代码:class Point:def __init__(self, x, y):self.x = xself.y = y3.2 算法步骤3.2.1 排序首先,将所有点按照横坐标进行排序。
可以使用快速排序或归并排序等算法来实现排序功能。
def sort_points(points):# 使用快速排序按照横坐标进行排序# ...3.2.2 分治求解将排序后的点集平均划分为左右两部分,并递归求解最近点对。
def closest_pair(points):n = len(points)# 如果点集中只有两个点,则直接返回这两个点和它们之间的距离if n == 2:return points, distance(points[0], points[1])# 如果点集中只有三个点,则直接计算出最近点对if n == 3:d1 = distance(points[0], points[1])d2 = distance(points[0], points[2])d3 = distance(points[1], points[2])if d1 <= d2 and d1 <= d3:return [points[0], points[1]], d1elif d2 <= d1 and d2 <= d3:return [points[0], points[2]], d2else:return [points[1], points[2]], d3# 将点集平均划分为左右两部分mid = n // 2P_left = points[:mid]P_right = points[mid:]# 分别在左右两部分递归求解最近点对closest_pair_left = closest_pair(P_left)closest_pair_right = closest_pair(P_right)# 在左右两部分求得的最近点对中,选择距离更小的那一对作为候选解if closest_pair_left[1] < closest_pair_right[1]:min_pair, min_distance = closest_pair_leftelse:min_pair, min_distance = closest_pair_right3.2.3 查找更近点对在区间[P_left[-1].x, P_right[0].x]内,查找可能的更近点对。
最近点对问题

算法分析与设计最近对问题最近对问题问题描述:在二维平面上的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 <stdio.h>#include <stdlib.h>#include <math.h>#define NUM 1000typedef 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){int i,nump,numl;N* qPre;N* qLast;if(num == 1 )return;if(num%2&&num != 2){numl = num/2;nump = num/2;nump++;}else{numl = num/2;nump = num/2;}qPre = (N*)malloc(sizeof(N)*nump);qLast = (N*)malloc(sizeof(N)*numl);for(i = 0;i < nump;i++)qPre[i] = q[i];for(i = 0;i<numl;i++)qLast[i] = q[nump+i];MergeSort(qPre,nump,mode);MergeSort(qLast,numl,mode);Merge(qPre,qLast,q,nump,numl,mode);}void Merge(N *pre,N *last,N *total,int nump,int numl,int mode){ int i = 0,j = 0,k = 0;while( i< nump && j< numl ){if(mode == 0){if(pre[i].x > last[j].x ){total[k++] = pre[i++];}else{total[k++] = last[j++];}}else{if(pre[i].y > last[j].y ){total[k++] = pre[i++];}else{total[k++] = last[j++];}}}if(i == nump){for(i = j; i < numl; i++)total[k++] = last[i];}else{for(j = i; j < nump; j++)total[k++] = pre[j];}}void computeShortestDistance(N* data , int num ,int result[4]){FILE *fo;int i,j,l = 0;int *datax,*datay;double dis = 666666,temp;datax = (int*)malloc(sizeof(int)*1000);datay = (int*)malloc(sizeof(int)*1000);for(i =0; i<num ;i++){datax[i] = data[i].x;datay[i] = data[i].y;}for(i = 0;i<num;i++){for(j = i+1;j<num;j++)if((temp = (datax[i] - datax[j])*(datax[i] - datax[j]) + (datay[i] - datay[j])*(datay[i] - datay[j])) < dis){dis = temp;result[0] = datax[i];result[1] = datay[i];result[2] = datax[j];result[3] = datay[j];}}printf("\n蛮力法:\n");printf("shortest dis: %f",sqrt(dis));}void generateDots(int number){FILE *fo;int i,n1,n2;if(!(fo = fopen("data.txt","w"))){printf("open file fail");exit(1);}for(i = 0;i< number;i++){srand((i*i));n1 =rand()%8000;srand(time(NULL)*i*i);n2 = rand()%6000;if(i%2)fprintf(fo,"%d %d\n",n1,n2);elsefprintf(fo,"%d %d\n",n2,n1);}fclose(fo);}int main(){ FILE* fo;N* data;int i;N n1,n2;double dis;int re[4];// 生成数据generateDots(NUM);data = (N*)malloc(sizeof(N)*1000);if(!(fo = fopen("data.txt","r"))){printf("open file fail");exit(1);}for(i = 0;i < NUM;i++){fscanf(fo,"%d %d",&data[i].x,&data[i].y);}fclose(fo);// 合并排序,排好序的数据放置到data 中。
最近点对算法

最近点对算法
最近点对算法是一种计算平面上最近的两个点的算法。
该算法是计算机科学中的一个基本问题,也是计算几何学的研究方向之一。
最近点对问题是指在平面上给定n个点,找出其中距离最近的两个点。
该问题的一个简单暴力解法是对每对点进行距离计算,然后选取距离最小的一对。
但该算法的时间复杂度为O(n^2),当n较大时效率较低。
因此,研究者提出了更高效的算法。
其中一种著名的解法是分治法,该算法的时间复杂度为O(nlogn)。
该算法的思路是将点集分成两个子集,然后递归地计算每个子集中的最近点对,并找出跨越两个子集的最近点对。
除分治法外,还有其他更优秀的最近点对算法,如随机增量法、基于网格的算法等。
最近点对算法在计算机科学、地理信息系统、机器人技术等领域有广泛应用。
- 1 -。
求最近点对的随机算法.doc

求最近点对的随机算法分治法求解需O(nlogn)时间,而用随机算法求解可达到O(n)时间。
对于给定的平面上的n个点(x i,y i)( i=1,2,…,n)和一个距离δ,以δ为尺寸可以构造一个(逻辑上的)网格,该网格以(min{x i},min{y j})为网格的最左下点,之后以步长δ不断向右、向上伸展为长方形网格;使得(max{x i},max{y j})也含在其中。
由于所有的点均在长方形网格中,最近点对也必在其中。
对每个尺寸为δ×δ的方格,分别向左向上、向右向上、向左向下、Γ(i=1,2,3,4)。
向右向下各扩展一格,可得4个2δ×2δ的方格iδ2定理:设已知平面上的某两点的距离为δ。
若最近点对中的一个点落在某个δ×δ方格δΓ中,Γ(i=1,2,3,4)中,则在上述的4个2δ× 2δ方格iδ2至少有一个同时含有最近点对的两个点。
推论:若已知平面上的某两点的距离为δ,且算法对长方形网格中每一个2δ×2δ方格中的所有点对,均一一计算其距离,则该算法一定可以找出最近点对。
算法:1)在点集S(|S|=n)中随机地取一个子集T,使得|T|=⎣n⎦。
(按随机取样算法的分析,n个中取m个(m≤n)时间为O(n))2)对T中的所有点对逐一计算距离,求出最近点对距离δ(T)。
(点对数为⎣n⎦(⎣n⎦-1)/2,每个点对计算时间为O(1),故总的计算时间为O(⎣n⎦2)= O(n)。
)3)以δ(T)为尺寸构造一个(逻辑上的)长方形网格,(设长方形的横向共有m格,纵向共有r格。
)4) 如果m*r ≤cn (c 可取2~10,取何值合适见后面的讨论),则开设一个m×r 的指针矩阵P 、和一个m×r 的计数矩阵Q , 然后逐一扫描S 中的点s k :如果s k 落在方格ij δΓ中(i,j 分别表示所在方格横向、纵向位置),则把该点放入P[i,j]所指的链表内,Q[i,j]增1,直至n 个点全部检查为止。
求两组点之间的最近点对实验总结

求两组点之间的最近点对实验总结在计算几何学和算法设计中,求两组点之间的最近点对是一个重要且常见的问题。
在这篇文章中,我将从简到繁地探讨这个主题,深入分析求解最近点对的算法,并进行实验总结,以便读者能更深入地理解这一概念。
一、什么是最近点对问题?最近点对问题是指在一个平面上给定n个点,要求在这些点中找到距离最近的两个点。
这个问题在实际中有着广泛的应用,比如计算机视觉中的物体识别、无人驾驶车辆的障碍物检测等都涉及到最近点对的计算。
设计高效的算法来解决最近点对问题具有重要意义。
二、最近点对的暴力解法最简单的方法是通过遍历所有点对,计算它们之间的距离,并找到最小值。
这种暴力解法的时间复杂度为O(n^2),空间复杂度为O(1),虽然简单易懂,但对于大规模的数据集来说效率较低。
三、分治法解决最近点对问题分治法是解决最近点对问题的常见方法,其基本思想是将点集分成两个子集,分别求解最近点对,然后再找出整个点集的最近点对。
在这个过程中需要用到分治、筛选和合并三个步骤。
具体算法流程如下:1. 将点集按照x坐标排序,找到中间线将点集分成左右两个子集。
2. 递归求解左右子集的最近点对。
3. 筛选出距离中线距离小于当前最近距离的点,将它们按照y坐标排序。
4. 在筛选后的点集中,以每个点为中心,向上下各取6个点。
5. 计算这些点之间的距离,更新最近距离。
6. 合并左右子集的结果,得到最终的最近点对。
使用分治法解决最近点对问题的时间复杂度为O(nlogn),效率较高,适用于大规模数据集。
四、实验总结及个人观点在进行最近点对的实验过程中,我发现分治法在处理大规模数据集时具有明显的优势,其算法设计合理、程序实现简单高效。
对于中等规模的数据集,暴力解法也能够得到较好的结果,但对于大规模数据集来说效率明显低于分治法。
我个人认为在解决最近点对问题时,应优先考虑使用分治法,并且可以根据数据规模选择不同的算法来达到更高的效率。
总结来说,求两组点之间的最近点对是一个重要且常见的问题,在实际应用中具有广泛的意义。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、算法分析
该算法的问题描述为:给定二维平面上的点集,求解距离最近的两个点,并计算出两点间的距离。
解决问题最初的思路为穷举法。
对所有两点间的组合计算其距离。
然后对其进行比较,找出最小值即可。
不过这样做的缺点是时间复杂度和空间复杂度十分庞大,消耗巨量资源。
如有n个点的平面上,计算的复杂度能达到n*n。
因此设计出一个高效的算法来代替穷举法是有现实意义的。
在思考问题的过程中,可以考虑使用分治法的思想,以x,y中x坐标作为划分区间的标准。
将平面点集一分为二。
求解其中的最小点对。
由此产生的问题为划分点附近两个区间中两点的距离可能小于各自区间中的最小值,产生了纰漏。
因此在在分治的过程中,加入分界线附近的点对最小值求解函数。
分界线区域内区间的选取标准为d。
其中d为左半区间和右半区间的最小值中的较小值。
在具体实现中,首先建立一个空数组存放按y坐标排序的点集,判断两个相邻点之间的y坐标差值,若大于d,则两点间距离一定大于d,可以直接跳过,继续判断下一个点对。
若小于d,则继续计算两点间的实际距离,若大于d,则跳过,小于d,将最小值更新为该点对距离。
二、算法实现
该算法的具体实现使用了两种求解方法,穷举法和分治法。
其中,穷举法用于判断最近点对算法实现结果的正确性。
算法使用的数据结构为数组,其中为了简单起见,将x轴坐标与y轴坐标分别存入两个数组,并新建一个数组record[],记录数组y的元素下标,用于绑定x坐标对应的y坐标。
在设计过程中使用到了比较排序算法,用于对x及y坐标排序,这并不增加其时间复杂度。
因此是可行的。
在分治算法中,设置划分区间的下限为3,即当区间内元素个数小于等于3时,不再使用分治。
在该设定下分为三种情况,元素数为1时,Min设为无穷。
元素数为2时,计算两点间距离并返回。
元素数为3时,一共计算三次距离,并取其最小值。
分治算法本身的思想为将分治与中线区间写在一个函数中,边界点的情况抛出,边界情况即元素数小于等于3时。
确保程序执行起始和终止位置的正确性。
三、实验结果
在实现过程中,选取点对数为5,输入不同的三组元素,进行算法正确性的验证。
1.(9,3) (7,10) (0,6) (5,8) (10,11)
实验结果如下图所示:
2.(34,5) (13,1) (5,62) (18,4) (32,15)
实验结果如下图所示:
3.(23,7) (47,19) (50,16) (35,54) (14,29) 实验结果如下图所示:。