在2D中查找最近的对象 - 是否可以在O(n)下进行优化?

时间:2015-01-26 16:34:36

标签: algorithm complexity-theory

想象一下有n个物体的2D平面。选择平面上的任何点,找出哪个对象最近。

显而易见的解决方案是计算从选定点到所有n个物体的距离并选择最短距离,但是不是更优化的算法?像二叉树这样的东西,巧妙地将飞机划分成区域等等?

编辑:让我们假设这些点"不移动"并且我们必须多次找到最近的物体。换句话说,如果我们想要的话,我们可以在开始时将对象排序成某种结构。

由于

2 个答案:

答案 0 :(得分:4)

在游戏编程领域," Space Partitioning"通常用于优化碰撞检测等代码。

一个非常简单的解释如下。您可以从2D空间中的对象开始:

Points in space

你使用算法来划分空间来制作"桶和#34;一起靠近的物体:

Partitioned space

现在,当你想要计算"哪个对象最接近某个点时#34;你只需要测试相邻桶中的那些:

Tests

如果您谨慎选择分区算法,这可以显着提高速度,因为您可以测试更少的点以获得贴近度。

有许多算法可以分析对象所在的空间,它们可以基于数组或各种类型的树。我在打字时看到Tommy's response列出了一些常见的内容。

互联网上有很多关于这个概念的文章,因为它是一种相当常用的模式。这是我过去读过的内容:

http://gameprogrammingpatterns.com/spatial-partition.html

答案 1 :(得分:2)

可能有数百种解决方案比O(n)更好。

k-d树或四叉树是最知名的。还有一些解决方案只涉及一个排序列表,它往往更适用于移动对象,但通常也更简单。

<强>四叉树

四叉树是一种树结构,其中每个节点都是一个有四个子节点的矩形。这四个孩子是原始的细分。假设您只插入点,在每个节点上测试将是:

  1. 这个节点有孩子吗?如果是这样:
    1. 哪个孩子明白了?
    2. 递给那个孩子。
  2. 如果不是:
    1. 在此节点添加点。
    2. 查看此节点现在存储的点数。
    3. 如果它现在太多了,那么创建孩子并将每个点推到适当的孩子身上。
  3. 您可以将节点划分为大小相同的孩子,或者尝试大致按照点的分布,例如将平均x和平均y作为分割位置。

    如果您要存储整个对象,则样式是否会插入到与对象重叠的每个节点以及子节点是否在边缘处相互重叠时会有所不同。如果您知道最大对象大小,那么这通常是要走的路,因为您在运行时测试的对象只需要考虑一个叶子节点。否则,您将不得不考虑几个节点的并集。

    否则搜索意味着找到您的点所在的叶节点,与该距离最小,然后向上走回树,直到您的测试点远离相关子边界而不是当前已知的最小距离。那时你知道你肯定不会找到更接近的东西。

    k-d tree

    k-d树也是树结构,但严格来说是二叉树。每个节点是1d跨度和分界点。子节点跨越不同的轴。

    E.g。一个节点可能知道它包含[0,10]中x的所有点。它会记录它的孩子只知道[0,7]中的x点和[7,10]中的x​​点。然而,它的两个子节点将用y表示。所以例如左边的人可能知道它覆盖了[0,6]中的y,而它的子节点覆盖了[0,1]和[2,6]中的y。

    因此,插入测试的伪代码与上面给出的四元组相同,但具体测试不同。在决定分割的位置时,取x的平均值或y的平均值更为常见。关于允许儿童重叠的相同意见适用。

    搜索遵循与四叉树相同的树行走逻辑。

    排序列表

    为了论证,我们假设您只对x进行排序。这是按照最低x范围排序的所有对象的单个列表。你知道每个物体的宽度。

    要找出哪个对象最接近某个点,首先要找到该对象将在列表中插入的索引。它已排序,因此您可以在O(log n)时间内完成此操作。

    计算插入索引处从点到对象的距离。那就是物体最远的上界。上限指示您需要在列表中向左或向右搜索的距离。同时向左和向右移动,更新上限,直到迭代器现在离x轴更远,而不是上限。那么上限就是正确的答案。