如何从二维平面n个点中寻找距离最近两个点?
如何理解分治算法
什么是分治算法?简单来说就是“分而治之”,也就是将原问题划分成n个规模较小的,并且结构与原问题相似的子问题,然后去递归地解决这些子问题,最后再合并其结果,就得到原问题的解。
对于分治算法来说,一般适合用递归来实现。分治算法的递归实现中,每一次递归都会涉及如下三个操作。
- 分解:将原问题分解成一系列子问题。
- 解决:递归地求解各个子问题。
- 合并:将子问题的结果合并成原问题。
分治算法的问题模型
对于可以采用分治算法来解决的问题,一般都需要满足以下几个条件:
- 原问题与分解成的子问题具有相同的模式。
- 原问题分解成的子问题可以独立求解,子问题之间没有相关性。
- 具有分解终止条件,也就是说,当问题足够小时,可以直接求解。
- 可以将子问题合并成原问题,而这个合并操作的复杂度不能太高,否则就起不到减小算法总体复杂度的效果了。
下面我们来结合一个例子来看一下分治算法的应用。我们来思考这么一个问题,在给定一组在二维空间中的n个点,如何快速找出距离最近的两点呢?最直观的想法就是通过遍历所有的点,然后求出所有点之间的距离,最后选出这些距离中的最小值对应的点,但是这种算法的时间复杂度是O(n*n),那有没有更快的方法呢?那就是分治算法。
为了方便起见,我们把N设置为2的k次幂,即N=2^k,k为正整数。下面我们来看一下这个问题是否满足分治算法的问题模型。
我们可以把问题N拆分成两个子问题,每个子问题等于原问题的一半。我们在二维平面中画一条垂线e,正好把N个点按照x轴位置拆分成2半(这个过程需要按照x轴排序,取中间的点),使得e的左右两边都有n/2个点。假设我们对e的左半边部分递归的求出的最近点对的距离为ld,e的右半边部分递归的求出的最近点对的距离为rd,接下来我们取出这两个距离中的最小值d=min(ld,rd),并且在e-d和e+d的位置上画两条垂线。这样一来,我们把二维空间划分成了3部分。如下图所示:
这样划分后,最近点对的出现位置只能有以下三种可能。
- 两个节点都在左边区域。
- 一个节点在左,一个节点在右。
- 两个节点都在右边。
其中,1和3我们已经在求解子问题的时候已经解决了,现在我们只需要求解第2个问题就好了,即在mid区域进行搜索。我们下面来看如何在mid区域进行搜索,我们需要把这个带状区域内的所有节点按照Y轴递增排序(我们可以在初始化的时候就缓存起来,后面直接使用就好),从Y排序最小的节点开始,我们连续检查带状区域内的每个点,计算所有比它的Y轴更大的点之间的距离,尝试找出距离比d更小的点对。
假设我们需要对节点p进行比较,我们考虑这样的一个空间,他是通过8个正方形(d/2*d/2)组成的一个长方形,p节点位于这个长方形的底边上,
我们只需要判断这个区域内的所有节点即可,因为一旦Y轴差距超过了d,就算x轴之差为0也会大于我们之前的距离d,所以不可能找出比 d 距离更小的点对。并且我们针对一个点,事实上只需要最多对比 7 次就能找出所有可能小于 d 的点对,因为每个小格子内部只可能出现1个节点,因为小格子内部的极限距离为 d / sqrt(2),也就是正方形的对角线,但是这个距离显然小于 d,如果这个正方形内部存在这样一个节点。那么之前对于 d 是左右区域内最小的点对距离的定义就被破坏了。所以不可能存在。
综上所述:这个问题是符合分治算法的问题模型的。下面我们来看一下代码实现。
`
import math
class Point:
def __init__(self,x,y):
self.x=x
self.y=y
def __str__(self):
return 'x='+str(self.x)+',y='+str(self.y)
class RecentPoint:
sortByXPoints = []
sortByYPoints = []
# p1=None
# p2=None
def getDistance(self, p1, p2):
xDis = (p1.x - p2.x) ** 2
yDis = (p1.y - p2.y) ** 2
return math.sqrt(xDis + yDis)
def findRecentPoint(self,data):
self.sortByXPoints=sorted(data,key=lambda point:point.x)
self.sortByYPoints=sorted(data,key=lambda point:point.y)
return self._findRecentPoint(0, len(data)-1)
def _findRecentPoint(self, p, q):
#区域内只有两对节点
if (q-p)<=1:
return self.getDistance(self.sortByXPoints[p], self.sortByXPoints[q])
middle=math.floor((p+q)/2)
ld=self._findRecentPoint(p, middle)
rd=self._findRecentPoint(middle+1, q)
# if(ld<rd):
# d=ld
# self.p1 = self.sortByXPoints[p]
# self.p2 = self.sortByYPoints[middle]
# else:
# d = rd
# self.p1 = self.sortByXPoints[middle+1]
# self.p2 = self.sortByYPoints[q]
d=min(ld,rd)
#中心点
e=self.sortByXPoints[middle].x + (self.sortByXPoints[middle+1].x - self.sortByXPoints[middle].x) / 2
LeftEdge = e - d
RightEdge = e + d
#接下来我们检查已 X 轴坐标 e 为中心点 从 e - d 开始 e + d 结束的带状区域内去检测最近点
#我们从中筛选所有带状区域内的点,并按照 Y坐标 的递增排序进行排序
insidePoint=[]
for point in self.sortByYPoints:
if(point.x>LeftEdge and point.x<RightEdge):
insidePoint.append(point)
#开始对比节点,寻找是否比d更短
for i in range(len(insidePoint)):
for j in range(1,8):
if(i+j>=len(insidePoint)):
break;
dis=self.getDistance(insidePoint[i],insidePoint[i+j])
if(dis<d):
d=dis
# self.p1=insidePoint[i]
# self.p2=insidePoint[i+j]
return d
data=[Point(1,6),Point(3, 4),Point(2, 5),Point(4, 8)]
s=RecentPoint()
print(s.findRecentPoint(data))
# print(s.p1)
# print(s.p2)
复制代码
` 今天的分享就到这里,更多硬核知识,请关注公众号,如果需要pdf文件,可以私信我哦。

如何从二维平面n个点中寻找距离最近两个点?的更多相关文章
- ZXing二维码生成在Unity3D中出错,数组超出界限的解决办法
错误截图: IndexOutOfRangeException: Array index is out of range.ZXing.Color32Renderer.Render (ZXing.Comm ...
- ASP.NET 生成二维码(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
最近做项目遇到生成二维码的问题,发现网上用的最多的是ThoughtWorks.QRCode和QrCode.Net两种方式.访问官网看着例子写了两个Demo,使用过程中发现两个都挺好用的,Thought ...
- 使用JavaScript生成二维码教程-附qrcodejs中文文档
使用javascript生成二维码 依赖jquery 需要使用到的库 https://github.com/davidshimjs/qrcodejs DIV <div id="qrco ...
- spring boot高性能实现二维码扫码登录(中)——Redis版
前言 本打算用CountDownLatch来实现,但有个问题我没有考虑,就是当用户APP没有扫二维码的时候,线程会阻塞5分钟,这反而造成性能的下降.好吧,现在回归传统方式:前端ajax每隔1秒或2秒发 ...
- python如何删除二维或者三维数组/列表中某维的空元素
如题,个人在使用python进行数据预处理过程中出现的问题,抽象成删除三维列表中某维为空的问题. 一.首先来看一下三维数组/列表的结构 仔细看下图就会很清楚了: 轴0即是去除第一个外括号后第一层(我把 ...
- 【牛客挑战赛30D】小A的昆特牌(组合问题抽象到二维平面)
点此看题面 大致题意: 有\(S\)张无编号的牌,可以将任意张牌锻造成\(n\)种步兵或\(m\)种弩兵中的一种,求最后步兵数量大于等于\(l\)小于等于\(r\)的方案数. 暴力式子 首先我们来考虑 ...
- 存在一个足够大的二维数组,每个数组中的值都是整数,使用javascript如何实现按每个数组中的平均值,从大到小排序这个二维数组?
这是牛客网上的一道题~ 题意:对数组排序,顺序是按照数组的平均值,即按照一个元素和平均值相减的绝对值的大小来排序...本例按这个绝对值递增排序 解题思想:先求出这个数组的平均值,如果 a<b,那 ...
- 生成二维码项目pom.xml中QRCode依赖报错
pom.xml报错如下: 解决方法: 1.将QRCode.jar包下载到E盘下 网盘下载地址: 链接:https://pan.baidu.com/s/1sY1NK5ekCkNH0uqraZMnKw 提 ...
- PHP二维码生成的方法(google APi,PHP类库,libqrencode等)
原文地址: http://blog.csdn.net/liuxinmingcode/article/details/7910975 ================================== ...
随机推荐
- Spring Boot 无侵入式 实现RESTful API接口统一JSON格式返回
前言 现在我们做项目基本上中大型项目都是选择前后端分离,前后端分离已经成了一个趋势了,所以总这样·我们就要和前端约定统一的api 接口返回json 格式, 这样我们需要封装一个统一通用全局 模版api ...
- ES服务的搭建(八)
看下图的淘宝页面,可以看到搜索有多个条件及搜索产品,并且支持多种排序方式,例如按价格:其实这块有个特点,就是不管你搜索哪个商品他都是有分类的,以及他对应的品牌,这两个是固定的,但其它参数不一定所有商品 ...
- 『无为则无心』Python序列 — 21、Python字典及其常用操作
目录 1.字典的应用场景 2.字典的概念 3.创建字典的语法 4.字典常见操作 (1)字典的增加操作 (2)字典的删除操作 (3)字典的修改 (4)字典的查找 (5)copy()复制 1.字典的应用场 ...
- 12、windows定时备份数据库
12.1.删除指定目录中的内容: del /Q E:\DATABAK\* copy 1.txt bak\a.txt 12.2.可用的备份计划: 1.脚本: BakScripts @echo off R ...
- flex发生错误积累。每次遇到错误记录一点点
error #2044: 未处理的 ioerrorevent: text=error #2036: 加载未完成 出现这个问题,因为我是要实现图片编辑裁剪,然后上传.没有上传成功,出现上面的这个错误, ...
- POJ 3449 Geometric Shapes 判断多边形相交
题意不难理解,给出多个多边形,输出多边形间的相交情况(嵌套不算相交),思路也很容易想到.枚举每一个图形再枚举每一条边 恶心在输入输出,不过还好有sscanf(),不懂可以查看cplusplus网站 根 ...
- Gym 100783C Golf Bot FFT
大致题意: 给你N个整数和M个整数,问这M个数中,有几个数可以表达成那N个整数中一个或者两个整数的和. 分析: 算是半个裸的FFT.FFT可以用来在nlongn时间内求高精度乘法,我们先模拟一下乘法. ...
- 如何在微信小程序的模板渲染中使用JS?
在微信小程序中使用模板渲染时,可能需要用JS对其进行处理. <view class="price text-red text-lg"> <!-- 价格保留两位小数 ...
- xcopy应用于版本合并
脚本 set src=C:\Users\cl\projectset dist=C:\Users\cl\projectxcopy %src% %dist% /y /e /exclude:exclude. ...
- FreeRTOS常用函数
一.任务 任务创建和删除xTaskCreate 任务创建xTaskDelete ...