[编程之美] PSet2.11 寻找最近点对



问题:

给定平面上N个点的坐标,找出距离最近的两个点。

数学描述:设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。


分析与解答:


解法一:蛮力法

         蛮力枚举两两点对之间的距离,然后得到最小的点对即为所求。这种方法需要两层循环,复杂度O(n^2)。精确来说应该是C(n,2),n个点中取两个,与取的顺序无关,因此应该为n(n-1)/2。下面是代码:

double MinDifference(Point point[] , int n)//n个点
{
	double minDiff = 0.0;
	double temp = 0.0;
	int firstIndex , secondIndex;
	for(int i=0 ; i<n ; i++)
		for(int j=i+1 ; j<n ; j++){
			temp = countDistance(point[i],point[j]);
			if(temp < minDiff){
				minDiff = temp;
				firstIndex = i;
				secondIndex = j;
			}
		}
}

解法二:分治法

参考自:http://www.cnblogs.com/king1302217/archive/2010/07/08/1773413.html

1)算法描述:已知集合S中有n个点,分治法的思想就是将S进行拆分,分为2部分求最近点对。算法每次选择一条垂线L,将S拆分左右两部分为SL和SR,L一般取点集S中所有点的中间点的x坐标来划分,这样可以保证SL和SR中的点数目各为n/2,
(否则以其他方式划分S,有可能导致SL和SR中点数目一个为1,一个为n-1,不利于算法效率,要尽量保持树的平衡性)
依次找出这两部分中的最小点对距离:δL和δR,记SL和SR中最小点对距离δ = min(δL,δR),如图1:

       以L为中心,δ为半径划分一个长带,最小点对还有可能存在于SL和SR的交界处,如下图2左图中的虚线带,p点和q点分别位于SL和SR的虚线范围内,在这个范围内,p点和q点之间的距离才会小于δ,最小点对计算才有意义。

     

       对于SL虚框范围内的p点,在SR虚框中与p点距离小于δ的顶多只有六个点,就是图二右图中的2个正方形的6的顶点。这个可以反推证明,如果右边这2个正方形内有7个点与p点距离小于δ,例如q点,则q点与下面正方形的四个顶点距离小于δ,则和δ为SL和SR中的最小点对距离相矛盾。因此对于SL虚框中的p点,不需求出p点和右边虚线框内所有点距离,只需计算SR中与p点y坐标距离最近的6个点,就可以求出最近点对,节省了比较次数。


(否则的话,最坏情形下,在SR虚框中有可能会有n/2个点,对于SL虚框中的p点,每次要比较n/2次,浪费了算法的效率)


3)算法时间复杂度:

首先对点集S的点x坐标和y坐标进行升序排序,需要循环2nlogn次,复杂度为O(2nlogn)

接下来在分治过程中,对于每个S'yL中的点,都需要与S'yR中的6个点进行比较

O(n)= 2O(n/2) + (n/2)*6 (一个点集划分为左右两个点集,时间复杂度为左右两个点集加上中间区域运算之和)

其解为O(n)< O(3nlogn)

因此总的时间复杂度为O(3nlogn),比蛮力法的O(n^2)要高效。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值