【发布时间】:2022-06-23 01:11:48
【问题描述】:
我在网上看到的在平面上找到最近点对的算法的大多数实现都有两个缺陷之一:要么它们无法满足 O(nlogn) 运行时间,要么它们无法适应某些点共享 x 坐标的情况。是否需要散列图(或等价物) 以最佳方式解决此问题?
大致而言,所讨论的算法是(根据 CLRS Ch. 33.4):
- 对于点 P 的数组,创建额外的数组 X 和 Y,使得 X 包含 P 中的所有点,按 x 坐标排序,Y 包含 P 中的所有点,按 y 坐标排序。
- 将点分成两半 - 放下一条垂直线,将 X 分成两个数组,XL 和 XR,并以类似方式划分 Y,使 Y L 包含直线左侧的所有点,YR 包含直线右侧的所有点,均按 y 坐标排序。
- 对每一半进行递归调用,将 XL 和 YL 传递给一个,XR 和 YR sub> 到另一个,并在每一半中找到最小距离 d。
- 最后判断是否有一对左一点右一点的分界线距离小于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