摘要
本文主要介绍CGAL库中对于空间搜索算法的实现,包括临近查找、区间查找以及KD树分割策略。
在CGAL空间搜索包中包含了精确和近似搜索的算法和实现,主要功能实现如下:
-
最近和最远临近搜索;
-
精确和近似搜索;
-
近似区间搜索;
-
近似K-最近和K最远临近搜索;
-
近似增量最近和增量最远搜索功能;
-
查询点和空间对象。
通常这些问题的给定条件是在d维空间中的点集(可采用笛卡尔坐标或者齐次坐标进行表示)。这些点使用树数据结构进行存储,因此能够确保快速查询。CGAL近似空间搜索用于搜索足够小的点集,以至于点集数据结构能够存储在内存中(与用于数据库中点集的近似搜索有所区别)。
一.临近搜索
空间搜索支持基于它们到查询对象的距离来浏览存储在空间数据结构中的d维空间对象的集合。查询对象可以是一个点也可以是任意的其他空间对象,如d维空间中的球,在空间数据结构中的对象则是d维空间中的点。
临近对象的数目通常在计算之前是未知的,这是因为数量通常是跟临近对象的属性或者空间距离相关的,比如查询距离巴黎最近的人口数量超过百万的城市。而K-最近搜索算法在搜索之前已经确定了搜索的数目。因此在未知搜索数目的情形下需要对搜索数目进行猜测,如果猜测数目较大,而实际搜索结果较小,则会执行较大的冗余计算,如果猜测数目较小而实际临近对象数量较多,则可能需要重新猜测计算,可以参考增量式临近搜索算法方面的内容。
空间搜索通常包括两个阶段:预处理和搜索阶段。在预处理阶段创建点集的搜索树结构(通常是KD-树),在搜索阶段引入搜索方法进行查询。
通过少量的修改,临近搜索算法可以用于离查询对象较远的对象进行查询。如果存在两个对象距离待查询对象的距离近似相等,近似查询中通常会返回这些对象中的一个。
在查询过程中,对于树结构中每个结点的访问需要考虑两个问题:
-
哪个子结点应该优先访问;
-
另外的子结点中是否存在临近对象的可能性。
通常计算距离使用给定的度量,K-临近搜索使用通用的距离类,但对于点的查询,我们可以更新距离,因为查询过程中通常是逐维度的改变,这就是具有正交距离类的正交K-临近搜索。
如上图所示,表示父矩形框,
和
分别表示当前步对应的子孩子,可以假定
距离查询坐标点q更近一些,令cd表示当前的维度,cv表示当前维度的值,此时可以得知
,并检查
是否有可能包含临近对象,由于
更接近于q点,因此有
,注意到对于每一维度有:
,这些坐标不受当前截断值的影响,沿cd方向的距离为
,
的计算表达式为
在CGAL中下面的两个类负责对正交距离(如加权Minkowski距离)标准的搜索策略进行实现。第二个类是针对增量式搜索的特化。
Orthogonal_k_neighbor_search<Traits, OrthogonalDistance, Splitter, SpatialTree>
Orthogonal_incremental_neighbor_search<Traits, OrthogonalDistance, Splitter, SpatialTree>
另外两个类则是针对广义距离概念如Manhattan距离(用于矩形的查询)定义的标准搜索策略,同理第二个类也是为增量式搜索提供的特化类:
K_neighbor_search<Traits, GeneralDistance, Splitter, SpatialTree>
Incremental_neighbor_search<Traits, GeneralDistance, Splitter, SpatialTree>
区间搜索算法
CGAL的Kd_tree类的search方法实现区间搜索功能,该方法通过模板实现,带有一个输出迭代器指针以及FuzzyQueryItem(可以是Fuzzy_iso_box或者Fuzzy_sphere)概念模型,针对于大数据集的区间搜索,用户可以指定bucket_size为一个较大的值如100,这样进行查询的时间将低于使用默认的bucket_size值,另外不要忘记CGAL定义近似搜索和精确搜索是通过定义误差参数实现的。若误差参数为零,则为精确搜索。
分割策略
用户可以根据数据自身的特点选择适当的分割策略,分割策略用于分割超平面的定义,每一种分割超平面都有最坏的时间复杂度,这可能将数据生成一个线性树或者导致栈溢出,选择适当的分割策略将可以解决这个问题。CGAL提供一下分割策略:
Midpoint_of_rectangle | 该策略以矩形最长边中垂线作为分割线 |
Midpoint_of_max_spread |
|
Sliding_midpoint | CGAL默认的分割策略,这是一个Midpoint_of_rectangle的修改版,在分割时,策略与Midpoint_of_rectangle一致,如果分割后两边都有数据点,则继续Midpoint_of_rectangle策略,如果一侧没有点,则不再执行分割。 |
Median_of_rectangle | 沿矩形的最长边进行分割,分割位置通过数据点沿当前维度的中值进行计算。 |
Median_of_max_spread | 沿矩形的最长边进行分割,分割位置通过数据点沿当前维度的中值进行计算。 |
Fair | 该策略是中点法和中值法的一个折中处理。该方法使矩形的分割以最大的长宽比作为上限。这个上限比值在Fair的构造函数中赋值。在满足此范围的分割值中,它选择使点具有最大分布的分割。它以尽可能最均匀的方式分割点,但要保持对所得矩形的长宽比的上限。 |
Sliding_fair | 该策略是Fair策略和Sliding_midpoint策略的折中,该策略认为符合以下两个条件的分割是较好的分割:
与Fair策略类似,该策略同样保持一个长宽比例的上限,在可能的分割值中选择使点具有最大分布的分割值。需要计算中值切割以及极限切割(根据长宽比例的极限计算),如果中值分割处于极限分割之间,则选择中值分割,如果不在,则在极限分割中选择最接近中值分割的情形。如果所有的点仅处于分割线的一侧,则滑动分割线至分割线遇到第一个点,该方法有可能打破长宽比例的限制,但是不会产生空格子。 |
想要了解更多关于CGAL的内容,请扫码关注微信公众号: