原文:http://blog.youkuaiyun.com/jollyjumper/article/details/24125225
在地图上画一条线,找出沿线一定宽度的POI点,现在的做法时线上取若干点,用kd树保存,查询一个点是否在沿线时,找到kd树中离改点最近的点,判断距离到改点是否小于指定距离,虽然不是很完美(点要取得足够多才能避免落掉一些点),也不失为解决方法。
kd树(k dimension tree)实际上是决策树,每次找区分度最大(方差最大)的一条轴线进行二分,二分至叶子节点只包含一个点,查找最邻近点时先找到叶子节点,然后回溯其祖先节点以这个点的距离剪枝搜索。
复杂度:建立O(nlogn),查找O(n^(1-1/k)+m)。
有个libkdtree++:http://libkdtree.alioth.debian.org/
套用我另一篇博文的方法:http://blog.youkuaiyun.com/jollyjumper/article/details/23588777,切分非常简单,街道直接切分为矩形,这个矩形装在一个对应的水平竖直的矩形里内接,面积不超过大矩形的1/2,找grid问题不大。
过滤阶段标准做法应该是对曲线进行拟合,然后求点到该线的距离,只要距离小于指定距离,可以认定符合要求,但是拟合的曲线点非常多,计算照样是o(n)的,但这样最精确,如果怕复杂度高,而用户画的线一般比较规则的话,应该去掉冗余的点。
原文:baike.baidu.com/link?url=9QAERb8PzCQLhzteD_SjqZitykNSZCIHquRG_7GW2BlqrYxKQyy716MG5IIA-UNR0310BbcajPRfYUZ6T2r1T_
1简介
2应用背景
3实例
4构建算法
域名
|
数据类型
|
描述
|
Node-data
|
数据矢量
|
数据集中某个数据点,是n维矢量(这里也就是k维)
|
Range
|
空间矢量
|
该节点所代表的空间范围
|
split
|
整数
|
垂直于分割超平面的方向轴序号
|
Left
|
k-d树
|
由位于该节点分割超平面左子空间内所有数据点所构成的k-d树
|
Right
|
k-d树
|
由位于该节点分割超平面右子空间内所有数据点所构成的k-d树
|
parent
|
k-d树
|
父节点
|
算法:构建k-d树(createKDTree)
|
输入:数据点集Data-set和其所在的空间Range
|
输出:Kd,类型为k-d tree
|
1.If Data-set为空,则返回空的k-d tree
|
2.调用节点生成程序:
(1)确定split域:对于所有描述子数据(特征矢量),统计它们在每个维上的数据方差。以SURF特征为例,描述子为64维,可计算64个方差。挑选出最大值,对应的维就是split域的值。数据方差大表明沿该坐标轴方向上的数据分散得比较开,在这个方向上进行数据分割有较好的分辨率;
(2)确定Node-data域:数据点集Data-set按其第split域的值排序。位于正中间的那个数据点被选为Node-data。此时新的Data-set' = Data-set\Node-data(除去其中Node-data这一点)。
|
3.dataleft = {d属于Data-set' && d[split] ≤ Node-data[split]}
Left_Range = {Range && dataleft} dataright = {d属于Data-set' && d[split] > Node-data[split]}
Right_Range = {Range && dataright}
|
4.left = 由(dataleft,Left_Range)建立的k-d tree,即递归调用createKDTree(dataleft,Left_
Range)。并设置left的parent域为Kd;
right = 由(dataright,Right_Range)建立的k-d tree,即调用createKDTree(dataright,Right_
Range)。并设置right的parent域为Kd。
|
5查找算法
-
从root节点开始,DFS搜索直到叶子节点,同时在stack中顺序存储已经访问的节点。
-
如果搜索到叶子节点,当前的叶子节点被设为最近邻节点。
-
然后通过stack回溯:如果当前点的距离比最近邻点距离近,更新最近邻节点.然后检查以最近距离为半径的圆是否和父节点的超平面相交.如果相交,则必须到父节点的另外一侧,用同样的DFS搜索法,开始检查最近邻节点。如果不相交,则继续往上回溯,而父节点的另一侧子节点都被淘汰,不再考虑的范围中.
-
当搜索回到root节点时,搜索完成,得到最近邻节点。