用于在大型集合中找到距离最远的球体的高效算法

时间:2010-02-16 21:28:13

标签: algorithm collections geometry comparison

我收集了10000到100000个球体,我需要找到最远的球体。

这样做的一个简单方法是简单地将所有球体相互比较并存储最大距离,但这感觉就像是算法的真正资源耗费。

Spheres以下列方式存储:

Sphere (float x, float y, float z, float radius);

方法Sphere :: distanceTo(Sphere& s)返回球体两个中心点之间的距离。

示例:

Sphere *spheres;
float biggestDistance;

for (int i = 0; i < nOfSpheres; i++) {
    for (int j = 0; j < nOfSpheres; j++) {
        if (spheres[i].distanceTo(spheres[j]) > biggestDistance) {
            biggestDistance = spheres[i].distanceTo(spheres[j]) > biggestDistance;
        }
    }
}

我正在寻找的是一种算法,如果有的话,以某种方式以更智能的方式遍历所有可能的组合。

该项目是用C ++编写的(必须是这样),因此任何 以C / C ++以外的语言工作的解决方案都不太有用。

4 个答案:

答案 0 :(得分:32)

一组S点中任意两点之间的最大距离称为 diameter 。找到一组点的直径是计算几何中众所周知的问题。一般来说,这里有两个步骤:

  1. 找到由每个球体的中心组成的三维凸包 - 例如,使用CGAL中的 quickhull 实现。

  2. 找到最远的船体上的点。 (船体内部的两个点不能是直径的一部分,否则它们会在船体上,这是一个矛盾。)

  3. 使用quickhull,您可以在平均情况下的O(n log n)和O(n 2 )最坏情况运行时间中执行第一步。 (实际上,quickhull明显优于所有其他已知算法。)如果可以保证关于球体排序的某些属性,则可以保证更好的最坏情况界限,但这是一个不同的主题。

    第二步可以用Ω(h log h)完成,其中h是船体上的点数。在最坏的情况下,h = n(每个点都在船体上),但如果你有数以千计的随机球体,这是不太可能的。通常,h会比n小得多。这是 an overview of this method.

答案 1 :(得分:3)

您是否可以将这些球体存储在BSP Tree中?如果这是可以接受的,那么你可以从寻找包含相距最远的球体的树的节点开始。然后你可以继续沿树走下去,直到你到达单个球体。

答案 2 :(得分:2)

您的问题看起来像是可以使用图表解决的问题。由于从球体A到球体B的距离与从球体B到球体A的距离相同,因此您可以最大限度地减少必须进行的比较次数。

我认为你在这里看到的被称为Adjacency List。您可以构建一个,然后遍历它以找到最长的距离。

您可以使用的另一种方法仍然会给你一个O(n ^ 2)但你可以减少你必须进行的比较次数。您可以将计算结果存储到哈希表中,其中键是边的名称(因此AB将保持从A到B的长度)。在执行距离计算之前,请检查哈希表中是否存在AB或BA。

修改

使用adjacency-list方法(基本上是Breadth-First Search)得到O(b ^ d)或最坏情况O(| E | + | V |)复杂度。

答案 3 :(得分:2)

保罗让我的大脑思考,你可以通过改变来优化一下

for (int j=0; j < nOfSpheres; j++) 

for (int j=i+1;  j < nOfSpheres; j++) 

您不需要将球体A与B AND B比较为A.这将使搜索O(n log n)。

---加法-------

使计算费用昂贵的另一件事是DistanceTo计算。

distance = sqrt((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2)

那是很多数学。您可以通过检查是否

来减少它
((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2 > maxdist^2

删除sqrt直到结束。