Algorithm 二维网格上最近物体的搜索算法

Algorithm 二维网格上最近物体的搜索算法,algorithm,2d,multidimensional-array,coordinate-systems,Algorithm,2d,Multidimensional Array,Coordinate Systems,假设您有一个二维网格,网格上的每个点都有x个对象(x>=0)。我很难想出一个干净的算法,当用户指定一个坐标时,该算法会找到最近的坐标(包括指定的坐标),上面有一个对象 为了简单起见,我们假设如果两个坐标距离相同,那么将返回第一个坐标(或者如果您的算法不以这种方式工作,那么最后一个坐标就无关紧要) 编辑:距离为1的坐标必须为1上、下、左或右。对角线以外的坐标为2 作为旁注,什么是伟大的免费在线算法参考?如果你有一个对象列表 如果列表中有所有对象的所有位置,这会容易得多,因为您不需要搜索所有的空方块

假设您有一个二维网格,网格上的每个点都有x个对象(x>=0)。我很难想出一个干净的算法,当用户指定一个坐标时,该算法会找到最近的坐标(包括指定的坐标),上面有一个对象

为了简单起见,我们假设如果两个坐标距离相同,那么将返回第一个坐标(或者如果您的算法不以这种方式工作,那么最后一个坐标就无关紧要)

编辑:距离为1的坐标必须为1上、下、左或右。对角线以外的坐标为2


作为旁注,什么是伟大的免费在线算法参考?

如果你有一个对象列表

如果列表中有所有对象的所有位置,这会容易得多,因为您不需要搜索所有的空方块,并且可以执行确定离您最近的方块。循环浏览对象列表并按如下方式计算距离:

Define your two points. Point 1 at (x1, y1) and Point 2 at (x2, y2).

    xd = x2-x1
    yd = y2-y1
    Distance = SquareRoot(xd*xd + yd*yd)
然后选择距离最短的一个

如果您只有一个2D阵列

但是,如果所描述的问题假设一个二维数组,在该数组中,如果不首先搜索所有对象,就无法列出对象的位置,则必须执行螺旋循环

搜索“”时会出现一些有趣的链接。但是,在阵列周围,这不会从任意点开始工作并向外螺旋,但会给您一些关于如何实现所需目标的好主意

下面是一个关于在二维数组中按螺旋顺序填充值的示例

无论如何,以下是我将如何解决这个问题:

给定点
p
,创建一个向量对,指定
p
周围的区域

所以如果
p=4,4
那么向量对将是
3,3 | 5,5

循环这些边界中的每个值

for x = 3 to 5
    for y = 3 to 5
        check(x,y)
    next
next
如果找到值,则退出。如果不是,请将边界再次增加1。所以在这种情况下,我们将使用2,2 | 6,6

在循环检查值时,确保没有进入任何负索引,并且确保没有超过数组的大小

此外,如果将边界扩展n次,则只需循环外部边界值,而无需重新检查内部值

哪种方法更快?

这完全取决于:

  • 阵列的密度
  • 分配技术
  • 对象数
阵列密度

如果有一个500x500数组,其中有两个对象,那么循环列表的性能总是优于螺旋

分发技术

如果存在分布模式(即对象倾向于彼此聚集),则螺旋可能执行得更快

对象数量

如果有一百万个对象,螺旋可能会执行得更快,因为列表技术要求您检查和计算每个距离

与列表解决方案每次都必须检查每个对象这一事实相比,通过计算空间被填满的概率,您应该能够计算出最快的解决方案


但是,使用列表技术,您可以进行一些智能排序以提高性能。这可能是值得研究的。

如果你的物体很密集,那么搜索附近的点可能是找到最近的物体的最好方法,从中心向外旋转。如果您的对象是稀疏的,那么一个或相关的数据结构(R树等)可能会更好。下面是一个例子


我不知道一个好的在线算法参考,但我可以说,如果你打算写比偶尔多行的代码,节省你的钱购买将是值得的。网上有一些基于这本书的讲座,这些讲座都经过了作者的精心注释,但它们只涵盖了这本书的一部分。这是你需要拥有的少数几本书之一。

更新

有了新的信息:

假设一个坐标是对角的 还有2分钟吗

这个算法可以工作。该算法以螺旋式的方式向外搜索,从内部开始测试每个“环”中的每个点

请注意,它不会处理越界情况。所以你应该改变这个来满足你的需要

int xs, ys; // Start coordinates

// Check point (xs, ys)

for (int d = 1; d<maxDistance; d++)
{
    for (int i = 0; i < d + 1; i++)
    {
        int x1 = xs - d + i;
        int y1 = ys - i;

        // Check point (x1, y1)

        int x2 = xs + d - i;
        int y2 = ys + i;

        // Check point (x2, y2)
    }


    for (int i = 1; i < d; i++)
    {
        int x1 = xs - i;
        int y1 = ys + d - i;

        // Check point (x1, y1)

        int x2 = xs + i;
        int y2 = ys - d + i;

        // Check point (x2, y2)
    }
}
int xs, ys; // Start coordinates

if (CheckPoint(xs, ys) == true)
{
    return (xs, ys);
}

for (int d = 0; d<maxDistance; d++)
{
    for (int x = xs-d; x < xs+d+1; x++)
    {
        // Point to check: (x, ys - d) and (x, ys + d) 
        if (CheckPoint(x, ys - d) == true)
        {
            return (x, ys - d);
        }

        if (CheckPoint(x, ys + d) == true)
        {
            return (x, ys - d);
        }
    }

    for (int y = ys-d+1; y < ys+d; y++)
    {
        // Point to check = (xs - d, y) and (xs + d, y) 
        if (CheckPoint(x, ys - d) == true)
        {
            return (xs - d, y);
        }

        if (CheckPoint(x, ys + d) == true)
        {
            return (xs - d, y);
        }
    }
}
intxs,ys;//起始坐标
//检查点(xs、ys)

对于(int d=1;d而言,以下简单解决方案假设您可以负担每个网格单元存储额外信息的费用,并且允许将新对象添加到网格的时间成本相对较高

其思想是,每个单元格都有一个对最近占用的单元格的引用,因此允许O(1)个查询时间。 每当将对象添加到位置(i,j)时,对周围的单元格进行扫描,覆盖越来越大的环。对于每个被扫描的单元格,评估其当前最近占用的单元格引用,并在必要时进行替换。当最后一个被扫描的环完全没有修改时,该过程结束。在最坏的情况下,该过程扫描所有网格单元格,但最终会变得更好当网格变得足够密集时


此解决方案易于实现,可能会有很大的空间开销(取决于网格在内存中的组织方式),但提供了最佳查询时间。

我确实知道所有对象的位置,但这有什么帮助?因为您可以循环查看整个对象列表,计算该对象与起点之间的距离,并找到最短的一个。仔细想想,如果速度不够快,这可能并不总是最快的解决方案重要的是,这取决于你的搜索空间有多大。它比外部螺旋算法简单得多。是的,这就是我一开始所做的。现在我有了一个通过网格的表示,我想利用它的方法可能是