【问题标题】:Finding closest pair of points in the plane with non-distinct x-coordinates in O(nlogn)在 O(nlogn) 中找到具有非不同 x 坐标的平面中最近的一对点
【发布时间】:2022-06-23 01:11:48
【问题描述】:

我在网上看到的在平面上找到最近点对的算法的大多数实现都有两个缺陷之一:要么它们无法满足 O(nlogn) 运行时间,要么它们无法适应某些点共享 x 坐标的情况。是否需要散列图(或等价物) 以最佳方式解决此问题?

大致而言,所讨论的算法是(根据 CLRS Ch. 33.4):

  1. 对于点 P 的数组,创建额外的数组 X 和 Y,使得 X 包含 P 中的所有点,按 x 坐标排序,Y 包含 P 中的所有点,按 y 坐标排序。
  2. 将点分成两半 - 放下一条垂直线,将 X 分成两个数组,XL 和 XR,并以类似方式划分 Y,使 Y L 包含直线左侧的所有点,YR 包含直线右侧的所有点,均按 y 坐标排序。
  3. 对每一半进行递归调用,将 XL 和 YL 传递给一个,XR 和 YR sub> 到另一个,并在每一半中找到最小距离 d
  4. 最后判断是否有一对左一点右一点的分界线距离小于d;通过几何论证,我们发现对于分割线距离d内的每个点,我们可以采用只搜索接下来的7个点的策略,这意味着被分割的子问题的重组只是一个O (n) 步骤(即使它看起来 n2 乍一看)。

这有一些棘手的边缘情况。人们处理这个问题的一种方法是在每个重组步骤(例如here)从分割线对距离 d 的点进行排序,但这会导致 O(nlog2n) 解决方案。

人们处理边缘情况的另一种方法是假设每个点都有一个不同的 x 坐标(例如 here):注意最接近于 Pyl 的 sn-p(或 YL我们称之为)如果 Y 中一个点的 x 坐标是 R)。请注意,如果所有点都位于同一垂直线上,这将导致我们在 C++ 中写入数组的末尾,因为我们将所有 n 点写入 YL

因此,当点可以具有相同的 x 坐标时,棘手的一点是将 Y 中的点分为 YL 和 YR,具体取决于点是否 Y 中的 p 在 XL 或 XR 中。 CLRS 中的伪代码是(为简洁起见略作编辑):

for i = 1 to Y.length
    if Y[i] in X_L
        Y_L.length = Y_L.length + 1;
        Y_L[Y_L.length] = Y[i]
    else Y_R.length = Y_R.length + 1;
        Y_R[Y_R.length] = Y[i]

但是,如果没有伪代码,如果我们使用普通数组,我们没有一个神奇的函数可以在 O(1) 时间内确定 Y[i] 是否在 X_L 中。如果我们确信所有 x 坐标都是不同的,那么当然 - 我们知道 x 坐标小于分界线的任何东西都在 XL 中,因此通过一次比较我们知道要使用哪个数组将 Y 中的任意点 p 划分为。但是在 x 坐标 不一定不同的情况下(例如,在它们都位于同一垂直线上的情况下),我们是否需要哈希图来确定 Y 中的点是否在XL 或 XR 并在 O(n) 时间内成功将 Y​​ 分解为 YL 和 YR ?还是有其他策略?

【问题讨论】:

  • 围绕 (0,0) 旋转所有点是相当简单的,以保证没有一对具有相同的 X 或相同的 Y。这一步本身应该花费 NlogN 时间。不知道你为什么这么反对使用哈希映射?
  • @BingWang 并不反对它,只是想知道我是否错过了使用更基本数据结构的策略——就像我说的那样,我在网上找不到符合我的两个标准的解决方案,即考虑到这个算法有多有名,这似乎很奇怪,所以我想我可能会遗漏一些简单的东西。
  • Tardos & Kleinberg 建议用它在 X 中的位置来注释每个点。你可以在 N 时间内这样做,或者,如果你真的非常想这样做,你可以在排序操作中这样做。使用此注释,您可以进行 O(1) 分区,然后在 O(1) 中获取 Xl 中最右侧点的位置 pr,使用它来确定 Y 中的点进入 Yl 的天气(位置 pr)。

标签: algorithm geometry closest-points


【解决方案1】:

是的,这里至少有两种方法。

第一个,正如 Bing Wang 所建议的,是应用轮换。如果角度足够小,这相当于在通过 x 比较后通过 y 坐标打破平局,无需其他数学运算。

二是在G4G上调整算法,使用线性时间划分算法来划分实例,使用线性时间排序合并来征服它。大概没有这样做是因为作者看重排序相对于前面提到的大多数编程语言中的算法的简单性。

【讨论】:

  • 确保我理解你提出的方案:在当前的 G4G 算法中,他们使用 O(1) 时间将输入数组 P 分成左右两半,并且 O(nlogn)在每个重组步骤中按 y 坐标对点条进行排序的时间。相反,您建议我们做两种 O(n) 工作 - 首先,使用 O(n) 时间将输入 P 划分为子数组,这些子数组将从按 y 坐标排序的最接近的 Utils 调用返回,这样我们就可以在 O(n) 时间内将它们合并在一起,并将其用作我们的集合 Y。对吗?
  • @jmath 你明白了!
【解决方案2】:

Tardos & Kleinberg 建议用它在 X 中的位置(索引)来注释每个点。 您可以在 N 时间内完成此操作,或者,如果您真的非常想这样做,您可以在排序操作中“免费”完成。

使用此注释,您可以进行 O(1) 分区,然后在 O(1) 中获取 Xl 中最右侧点的位置 pr,使用它来确定 Y 中的点进入 Yl 的天气 (位置 pr)。这不需要像哈希映射这样的额外数据结构,但它确实需要在 X 和 Y 中使用相同的位置。

注意: 对我来说,当多个点在 x 轴上具有相同坐标时,Y 的分区是唯一出现的问题,这对我来说并不是很明显。在我看来,跨分区所必需的比较的线性证明被打破了,但我只看到了你只需要 15 次比较的证明,而不是更严格的 7 点版本的证明,所以我不能确定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-02
    • 1970-01-01
    • 1970-01-01
    • 2014-03-20
    • 2017-05-22
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多