2.9 二维最近点对问题
2.9.1 问题描述
问题描述:二维平面上有n个点,如何找到距离最近的点?
2.9.2 暴力求解
1 算法思路
二维平面上有n个点,则有(n-1)+(n-1)+...+1=n(n-1)/2
个点对,依次遍历求出所有点对的距离即可。
2 时间复杂度分析
由1分析可知,即总共要求出n(n-1)/2
个距离,故时间复杂度O(n^2)
2.9.3 分治法求解
1 算法思路
核心思想:
- 数据预处理
- 划分中轴线
- 求出左边的最小距离
- 求出右半边的最小距离
- 求出中间的最小距离
- 比较这三个最小距离
① 数据预处理
因为这些点的位置是随机产生并保存在二维数组中,所以我们得先将这些点,按照x坐标从小到大排序,调整它们在二维数组中的次序。比如:最左边的点,它的位置就保存在二维数组的第一个元素中;
② 划分中轴线
把这些点在平面上分成左右两边。
问:依据什么来划分中轴线?
答:选择最中间的两个元素,求出它俩x坐标的平均值,设置为中轴线的坐标。
③ 求半边最小距离
左半边和右半边的求最小距离的方法是一样的。
假如我们现在求的是左半边,那就把左半边也看成一个整体,我们再把它分成左右两半,依次往下递归,越分越小。
问:递归何时中止?
答:分到点只剩很小的时候就终止,比如本文在后面附加的代码中,是当平面只剩下4个点时就不再切分。
④ 求中间的最小距离
问:中间区域应该划分多宽?
答:我们只需要考查中轴线左右两边距离小于d的点。理由是,距离中轴线大于d的那些点,它们和另一个半边的点的距离,肯定大于d,考查他们就没有意义了。
那么,现在我们只需要对上图的左侧2个点和右侧4个点分别进行比较即可。
如何进一步优化?
比如我们现在选取了左侧的m点,但实际上,我们不必跟右侧的4个点都比较,只需跟右侧的阴影部分(d*2d)以内的点进行比较,也就是,跟m点垂直距离在d以内的那两个点。
原因:如果两点之间垂直距离大于d,那么这两点间距必然大于d,考查他们也没有意义。
关于矩形的进一步说明
如果查阅过其他资料,或许你听过,我们划分出的dx2d区域中,最多只能有6个点。
因为我们已知两侧的最小距离为d,而d*2d的区域中的点是同一侧的。因此这些点的距离必然大于等于d,经过数学几何知识,我们可以算出这个区域最多只能有6个点。
2 时间复杂度分析
时间复杂度:O(nlog2n)
2.9.4 代码实现
① 数据预处理
在这里,我是采用了效率较高的快速排序算法。
具体的代码,请见2.6.2节快速排序
② 分治法
1 | public static double getByDivideConquer(double[][] points) { |