分治法详解二维最近点对问题

1 前言

转载请注明出处。

2 问题描述

问题描述:二维平面上有n个点,如何找到距离最近的点?
在这里插入图片描述

3 分治法

分治法:将一个规模较大的问题分解为规模较小的子问题,先求解这些子问题,然后将各子问题的解合并得到原问题的解的思路。
递归:直接或间接地调用自身方法。递归通常是解决分治的办法。

  • 递归缺点:具体执行步骤理解比较复杂;
  • 递归优点:易于实现,大体思路清晰。

4 暴力求解

4.1 算法思路

二维平面上有n个点,则有(n-1)+(n-1)+...+1=n(n-1)/2个点对,依次遍历求出所有点对的距离即可。

4.2 时间复杂度分析

由4.1分析可知,即总共要求出n(n-1)/2个距离,故时间复杂度O(n^2)

4.3 代码实现
	public static double getByBruteFoce(double[][] points) {
   
		int head=0;
		int tail=points.length-1;
		double minDist=getDistance(points,head,head+1);//初始化最小距离
		int [] minIndex=new int[] {
   head,head+1};//初始化最小点对序号
		for(int i=head;i<=tail-1;i++) {
   //遍历求距离
			for(int j=i+1;j<=tail;j++) {
   
				if(getDistance(points,i,j)<minDist) {
   
					minDist=getDistance(points,i,j);//更新点对最小距离
					minIndex[0]=i;//更新点对序号
					minIndex[1]=j;
				}
			}
		}
		return minDist;
	}

5 分治法求解

5.1 算法思路

核心思想:

  1. 数据预处理
  2. 划分中轴线
  3. 求出左边的最小距离
  4. 求出右半边的最小距离
  5. 求出中间的最小距离
  6. 比较这三个最小距离
5.1.1 数据预处理

因为这些点的位置是随机产生并保存在二维数组中,所以我们得先将这些点,按照x坐标从小到大排序,调整它们在二维数组中的次序。比如:最左边的点,它的位置就保存在二维数组的第一个元素中;

5.1.2 划分中轴线

把这些点在平面上分成左右两边。
依据什么来划分中轴线?
选择最中间的两个元素,求出它俩x坐标的平均值,设置为中轴线的坐标。

5.1.3 求半边最小距离

左半边和右半边的求最小距离的方法是一样的。
假如我们现在求的是左半边,那就把左半边也看成一个整体,我们再把它分成左右两半,依次往下递归,越分越小。
递归何时中止?
分到点只剩很小的时候就终止,比如本文在后面附加的代码中,是当平面只剩下4个点时就不再切分。

5.1.4 求中间的最小距离

中间区域应该划分多宽?
我们只需要考查中轴线左右两边距离小于d的点。
理由:距离中轴线大于d的那些点,它们和另一个半边的点的距离,肯定大于d,考查他们就没有意义了。
在这里插入图片描述
那么,现在我们只需要对上图的左侧2个点和右侧4个点分别进行比较即可。

如何进一步优化?
比如我们现在选取了左侧的m点,但实际上,我们不必跟右侧的4个点都比较,只需跟右侧的阴影部分(d*2d)以内的点进行比较,也就是,跟m点垂直距离在d以内的那两个点。
原因:如果两点之间垂直距离大于d,那么这两点间距必然大于d,考查他们也没有意义。
在这里插入图片描述

关于矩形的进一步说明
如果查阅过其他资料,或许你听过,我们划分出的d*2d区域中,最多只能有6个点。
因为我们已知两侧的最小距离为d,而d*2d的区域中的点是同一侧的。因此这些点的距离必然大于等于d,经过数学几何知识,我们可以算出这个区域最多只能有6个点。

5.2 代码实现
5.2.1 数据预处理

在这里,我是采用了效率较高的快速排序算法。

	//数据预处理:将点按照横坐标由小到大排序
	//快速排序
	private static double[][] quickSort(double[][] oldData) {
   
		double[][] newData=old
  • 33
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值