计算列表中两点最大距离的最有效方法是什么?

时间:2014-06-29 05:44:41

标签: algorithm geometry big-o

我有点L的列表(x, y)和通常的欧氏距离度量

enter image description here

如何找到此列表中两点的最大距离?或者,更正式地说:我如何找到

enter image description here

琐碎的方法

解决这个问题的最简单方法似乎是尝试一切:

def find_max_dist(L):
    max_dist = d(L[0], L[1])
    for i in range(0, len(L)-1):
        for j in range(i+1, len(L):
            max_dist = max(d(L[i], L[j]), max_dist)
    return max_dist

为了使计算更快,我可以使用循环中的平方距离并在最后返回根。

此方法的运行时复杂度为O(n^2),其中n是列表L的长度。 (以及恒定的空间复杂度)。

凸壳

显然,不能有任何比O(n)更快的算法,因为必须在列表中的每个元素上至少查看一次。

凸壳的元素之间的最大距离。但很容易证明凸包的计算至少在O(n log n)Graham's scan似乎是这样做的。但在找到复杂的船体后,我仍然需要获得最大距离。 我最终会以

结束
def find_max_dist_graham_triv(L):
    H = Graham_scan(L)
    return find_max_dist(L)

现在,这是我不确定的一点。我认为可以这样改进:

def find_max_dist_graham_c1(L):
    H = Graham_scan(L)  # Get ordered list of convex hull points
    max_dist = d(L[0], L[1])
    for i in range(0, len(L)-1):
        loop_max_dist = 0
        for j in range(i+1, len(L):
            curr_dist = d(L[i], L[j])
            if curr_dist < loop_max_dist:
                break
            loop_max_dist = curr_dist
            max_dist = max(loop_max_dist, max_dist)

    return max_dist

这个想法是,当你从一个凸包的一个点开始并从它的相邻点开始时,对角线会不断增加,达到最大值然后继续减小。不过,我不确定这是否属实。

直观地说,我会继续改进算法:一旦第一个内循环结束,我们就找到了该循环的“最长对角线”。该对角线将两个分离集中的所有其他船体点分开。每个较长的对角线必须由这两组中的点组成(正确吗?):

def find_max_dist_graham_c1(L):
    H = Graham_scan(L)  # Get ordered list of convex hull points
    max_dist = d(L[0], L[1])  # Get a fist idea what the longest distance might be

    i = 0
    p1 = L[i]  # Grab a random point
    loop_max_dist = 0
    for j in range(1, len(L):
        curr_dist = d(L[i], L[j])
        if curr_dist < loop_max_dist:
            break
        loop_max_dist = curr_dist
        max_dist = max(loop_max_dist, max_dist)
    # Every diagonal that is longer than the best one found with L[0]
    # has to have points in both of the following two sets (correct?):
    # [1...j] and [j+1...len(L)]

    # Try to find a neighboring diagonal that is longer.
    change = True
    while change:
        change = False
        if d(L[i-1], L[j+1]) > max_dist:
            max_dist = d(L[i-1], L[j+1])
            i -= 1
            j += 1
            change = True
        elif d(L[i+1], L[j-1]) > max_dist:
            max_dist = d(L[i+1], L[j-1])
            i += 1
            j -= 1
            change = True
    return max_dist

凸壳上的每个点P在凸包上都有一个点Q,因此PQ是包括P的最长对角线。但那么P也是Q的最长对角线的“终点”吗?

我真的不确定这个算法是否正确。它将在O(n log n)。

我想这个问题已得到很好的分析,所以有人可以留下一些注意事项吗?

虽然我有很多子问题但主要问题是:

查找点列表中点的最大距离的有效方法是什么?

2 个答案:

答案 0 :(得分:9)

你应该查看旋转卡尺(http://en.wikipedia.org/wiki/Rotating_calipers) - 它们被广泛用于那种问题。 而且,你的假设是错误的。对于凸多边形上的固定点 p :对角线可以首先增加,然后减小,然后增加,然后再次减小。至少,我遇到过这种情况。

启发式方法:选择 x 点。从中找出最远点 y 。从 y 中找到最远点 z d(z,y)是一个很好的估计。

说明对角线的图像:

enter image description here

1-> 2:增加; 2-> 3减少; 3-> 4增加; 4-> 5减少。这个数字可能不准确,将3和4点指向远离p的点(在同一条线上)。

答案 1 :(得分:0)

假设您有均匀分布的点数,您可以执行以下操作:

查找max_xmin_x作为最大和最小X坐标 - (O(n))。这些值应该可以帮助您选择常量k作为当前点集的“最佳”值。 k的不同值将仅影响算法的复杂性。

考虑一个类似矩阵的新数据结构,它是矢量或链接列表矢量的矢量,我们将其命名为structure,其中structure[i]是相应的矢量/链接列表(如上所述) 。按如下方式填充此数据结构:structure[i]应包含其x坐标位于[max_x+ik,max_x+(i+1)k]范围内的点,这将需要另一个O(n)时间和O(n)额外的空间。现在,您按structure[i]坐标对y的每个条目进行排序。完成此操作后,计算以下一组点之间的距离(强力)就足够了:structure[0]structure[structure.length()-1],每个其他{{1}的极值(第一个和最后一个索引处) }。

基本上这与进行凸包并开始计算船体上的点的距离几乎相同,不同之处在于选择正确的structure[i]可能会使其更快或更慢。最差的案例复杂度k和最佳案例复杂度O(n^2)O(nLg(n))将影响排序更大的点组或者有更多点来计算两者之间距离的交易。