此算法是确定两个阵列是否具有相同顺序的相同内容的好方法吗?

时间:2012-02-17 19:32:33

标签: algorithm geometry

所以我有两个数组,每个数组代表一个简单的闭合多边形,按顺序遍历点数组。最后一个元素与第一个元素相同。我正在为任何2个简单的闭合多边形实现一个等于算法。

Array A would be like this [pnt1, pnt2, pnt3, pnt4, pnt5, pnt6, pnt1]
Array B would be like this [pnt2, pnt3, pnt4, pnt5, pnt6, pnt1, pnt2]
Array C would be like this [pnt2, pnt1, pnt6, pnt5, pnt4, pnt3, pnt2]
Array D would be like this [pnt1, pnt2, pnt3, pnt5, pnt6, pnt4, pnt1]

数组A和B是相等的,因为这些点的顺序和点相同。数组A和C是相等的,因为这些点的顺序相同(但相反),出于同样的原因,B和C也是如此。

数组D不等于任何其他数组,因为点遍历无序。

所以我的算法如下:

1)比较数组的长度,必须包含相同的元素数 - 常数时间

2)在B组中找到A [0]为K - 线性搜索,线性时间

3)看A [1] = B [K + 1]等等,直到A [n],线性时间

自然索引会绕过数组的末尾,也许是通过mod运算符。

有没有比这更好的算法?

4 个答案:

答案 0 :(得分:2)

要点:

  1. 删除重复点
  2. 找到最小值的位置i
  3. 如果i-1处的值低于i + 1处的值,则反转该字符串(必须采用边缘情况,即i = 0或i = n-1)
  4. 旋转数组,使最小值位于头部
  5. 总复杂度:O(n)

    注意:步骤3和4不是绝对必要的。从第2步开始,您可以获得最小的位置,并从第3步获取方向。在比较两个不同的数组时,首先从最小值的* location * s开始比较,然后根据方向进行移动。

    例如:

    [pnt1,pnt2,pnt3,pnt4,pnt5,pnt6,pnt1] - > [pnt1,pnt2,pnt3,pnt4,pnt5,pnt6] - > [pnt1,pnt2,pnt3,pnt4,pnt5,pnt6]

    [pnt2,pnt3,pnt4,pnt5,pnt6,pnt1,pnt2] - > [pnt2,pnt3,pnt4,pnt5,pnt6,pnt1] - > [pnt1,pnt2,pnt3,pnt4,pnt5,pnt6]

    [pnt2,pnt1,pnt6,pnt5,pnt4,pnt3,pnt2] - > [pnt2,pnt1,pnt6,pnt5,pnt4,pnt3] - > [pnt3,pnt4,pnt5,pnt6,pnt1,pnt2] - > [pnt1,pnt2,pnt3,pnt4,pnt5,pnt6]

    [pnt1,pnt2,pnt3,pnt5,pnt6,pnt4,pnt1] - > [pnt1,pnt2,pnt3,pnt5,pnt6,pnt4] - > [pnt1,pnt2,pnt3,pnt5,pnt6,pnt4]

答案 1 :(得分:2)

要进行这样的比较,您可以检查一个数组是否是另一个数组的旋转(最后一个元素除外)。

首先,删除ElKamino指出的重复元素。基本上,你想知道是否可以通过旋转B的元素来获得A.

A=[x1, x2, ..., xk]时,B将以与A相同的顺序具有相同的内容,当且仅当B=[x3, x4, ..., xk, x1, x2]或类似的内容时。在这种情况下,B可以称为rotation of A。但是,这还不够,因为您还想检查订单是否相同但是相反。然后,您可以对B的反向或A的反向应用相同的过程。

<强>伪代码

def isSamePolygon(A, B):
    remove the last element of A and last element of B
    return isRotation(A, B) or isRotation(A, reverse(B))

def isRotation(A, B): // returns true if A is a rotation of B
    // create an array which has two copies of A.
    // e.g [a1, a2, ..., ai, a1, a2, ..., ai]
    if (size(A) != size(B))
        return false
    temp_array = concat(A, A)
    return true if temp_array contains the elements of B in the exact same order,
        false otherwise

<强>分析

isRotation的运行时间和空间复杂度在max(size(A),size(B))的大小上是线性的。这是因为创建temp_array需要大小为A的线性时间和线性空间。同样,检查A中是否包含B也需要线性时间才能运行。

如果我错了,请纠正我,但使用这种算法,你无法减少渐近的复杂性。但是,您可以优化它以更快地运行。如果size(A)>size(B),您可能想要交换A和B.此外;你可以同时检查反向,而不是两个电话。

答案 2 :(得分:2)

如果不允许预处理,这个问题最糟糕的情况是Omega(N),因为在另一个顶点中找到一个多边形的一个顶点可以进行N次比较。

所以没有比你的算法好多了,算法在最佳时间O(N)运行。 [但是,在2和3之间插入一个步骤来确定遍历顺序。]

如果允许预处理,则可以为每个多边形识别(X,Y)字典顺序中的第一个顶点。我们称之为主顶点。通过这样做,您将使算法的第1步无用,因为两个相等的多边形具有相同的主顶点,并且备用线性搜索。

更好的是,您可以通过从主顶点开始计算坐标上的CRC,将签名与多边形相关联。然后,只需通过比较签名,您就可以在时间O(1)中检测到具有高概率的不同多边形。

答案 3 :(得分:1)

我认为“简单”是指没有孔或自交叉的多边形,但是它可能仅在顶点处触及自身。例如,以下内容:

Pathological case

在你的情况下,这种情况可能并不重要,但有些polygon algorithms依赖于这些形状来形成构成复杂多边形的轮廓,因此能够应对它们很方便。

在这种情况下,这两个多边形应该相等:

P = ABCADEAFGAHIAJKA
Q = FGAHIAJKABCADEAF

某些给定的算法可能忽略了这一点,因为P中的第一个(和词典上最小的)顶点A被重复。但是,只要我们知道没有重复 edge ,我们就可以毫不费力地调整算法:

  1. P[0]中搜索Q
  2. Q[i]找到匹配项后,将P[1]Q[i-1]Q[i+1]进行比较(并进行适当的包装)。
  3. 如果两者都不匹配则返回1并且继续在P[0] 中搜索Q,从Q[i+1]开始。
  4. 在步骤2中找到匹配后,继续向前推进P并向前推进Q。可能会发现不匹配,在这种情况下,多边形不同,您可以立即停止(无需继续搜索P[0]的其他匹配项),或者您将遍历整个过程,并且它们是相同。
  5. 顺便说一句,如果你想使用一个算法,需要在轮廓中识别字典上最小的顶点,但是顶点可以重复,你可以通过考虑最小的相邻顶点或顺时针(或计数器)来打破关系 - 时钟,只要你是一致的)邻近的顶点。同样,这取决于不重复的边缘。