我在一组中有一组相当大的2D点(~20000),并且对于x-y平面中的每个点,想要确定该组中哪个点最接近。 (实际上,这些点的类型不同,我只想知道哪种类型最接近。而x-y平面是位图,比如640x480。)
从this answer到问题" All k nearest neighbors in 2D, C++"我有了制作网格的想法。我创建了n * m C ++向量并将这些点放在向量中,具体取决于它落入哪个bin。这个想法是你只需要检查垃圾箱中的点的距离,而不是所有的点。如果垃圾箱中没有任何点,则以螺旋方式继续相邻的垃圾箱。
不幸的是,之后我只读了Oli Charlesworth的评论:
不幸的是,不仅仅是邻近(考虑到单元格中的两个点 东边可能比东北方向的小区更接近, 例如;这个问题在更高的维度上变得更糟糕)。 而且,如果相邻的小区恰好小于10,该怎么办? 他们分?在实践中,你需要"螺旋式的"。
幸运的是,我已经找到了螺旋式代码(一个不错的C++ version here,并且在同一个问题中还有其他版本)。但我仍然没有解决问题:
如果我在一个单元格中找到一个点击,相邻单元格中可能会有更接近的击中(黄色是我的探测器,红色是错误的选择,绿色是实际的最近点):
如果我在相邻的小区中发现一个点击,那么在2步之外的小区中可能会有一个点击,正如Oli Charlesworth所说:
但更糟糕的是,如果我在两步之外的一个牢房中发现了一次撞击,那么在三步之外的撞击中仍然会有更接近的击中!这意味着我必须考虑所有具有dx,dy = -3 ... 3或49个细胞的细胞!
现在,在实践中,这不会经常发生,因为我可以选择我的bin大小,以便细胞足够填充。尽管如此,我还是希望得到一个正确的结果,而不是迭代所有点。
那我怎么知道何时停止"螺旋式"或者搜索?我听说有一种方法有多个重叠的网格,但我并不太了解它。是否有可能挽救这种网格技术?
答案 0 :(得分:1)
由于位图的尺寸不大,而您想计算每个 (x,y)
的最近点,您可以使用动态编程。
让V[i][j]
为(i,j)
到集合中最近点的距离,但考虑仅集合中“矩形”中的点[( 1,1),(i,j)]。
然后V[i][j] = 0
如果(i, j)
中有一个点,或V[i][j] = min(V[i'][j'] + dist((i, j), (i', j')))
其中(i', j')
是(i,j)
的三个邻居之一:
即
(i - 1, j)
(i, j - 1)
(i - 1, j - 1)
这为您提供了最小距离,但仅适用于“左上角”矩形。我们对“右上”,“左下”和“右下”方向也这样做,然后采取最小值。
复杂度为O(平面的大小),这是最佳的。
答案 1 :(得分:1)
对于您的任务,通常使用Point Quadtree
,尤其是当点数不均匀分布时。
要保存主存储器,您可以使用使用存储桶的PM或PMR-Quadtree。
你在你的细胞中进行搜索,在最坏的情况下,所有四元细胞都会在细胞周围进行搜索。
您还可以使用k-d tree
。
答案 2 :(得分:0)
一种解决方案是构建具有不同网格大小的多个分区。
假设您在级别1,2,4,8,...
创建分区现在,搜索网格大小为1的点(基本上是在9个方格中搜索)。如果搜索区域中有一个点,并且到该点的距离小于1,则停止。否则,请转到下一个网格大小。
与仅创建一个分区级别相比,您需要构建的网格数量大约是两倍。
答案 3 :(得分:0)
尝试解决方案
由于每个盒子平均有1个点,因此您将主要选择9个盒子并比较9个距离。可以根据您的数据集属性调整网格大小,以获得更好的结果。
此外,如果您的数据有很多差异,您可以尝试2级网格(甚至更多),因此如果选择有效并且在单个查询中返回超过50个点,则使用网格1开始下一个网格搜索/ 10大小...