【问题标题】:I need an algorithm for merging/joining a range of segments into a range of polylines我需要一种算法来将一系列段合并/连接到一系列折线中
【发布时间】:2017-01-10 09:38:02
【问题描述】:

我有一系列段,它们最多在它们的末端相互交叉。我想将这些线段合并成折线。

O(N_segments) 中是否有一种算法可以在不使用额外存储的情况下执行此操作(例如,无需为分段点构建树或其他一些空间数据结构并进行处理)?

我的段数很少,O(10)。因此,将它们放入像哈希表或映射(红黑树)这样的动态数据结构中可能会比最后的 O(N^2) 循环更昂贵,除非我将该数据结构放在堆栈上并避免任何内存分配(我使用的折线是使用small_vector 实现的,只要点数足够少,就可以避免分配。

目前我想出了这个:

polylines = []
// 1. Append each segment to a range of polylines, merging when possible:
for each segment in segments:
    for each polyline in polylines:
       merge_result = merge(segment, polyline)
       if (not merge_result) continue
       polyline = merge_result
       goto done

    // either polylines empty or no merge possible
    polylines.append(segment)

    done:
      continue

// 2. Try to merge the polylines among themselves until no more merges are possible
// Pure brute force, quadratic
done = false
while not done:
    for p1 in polylines: 
        for p2 in polylines[p1..end]:
            merge_result = merge(p1, p2)
            if not merge: continue
            p1 = merge_result
            polylines.remove(p2)
            done = false
            goto restart
    restart: continue

但是第二个循环显然是二次的,所以我想知道是否有更好的算法来合并/加入/组合一系列片段。

【问题讨论】:

  • 为什么要避免创建数据结构?我会创建一个分段端点的地图,以检测是否有多个分段在大约 O(n) 时间内共享一个端点。
  • A related post 建议计算端点的哈希值以加快搜索速度。
  • @MrSmith42 我处理 O(10) 段的顺序,所以除非我在堆栈上创建地图,否则创建动态地图的成本可能会超过最终 O(N) 的成本^2) 循环。这就是为什么我对没有额外数据结构的更好算法感兴趣的原因。我将尝试使用堆栈上的地图并对其进行基准测试。感谢您的建议。

标签: algorithm geometry spatial polyline segment


【解决方案1】:

我严重怀疑是否存在 O(n) 方法。

这是一个 O(n log(n)) 方法,用于检测具有完全相同坐标的线段末端。它使用“数据结构”,但它是一个非常简单的结构(只是一个向量):

1) 创建所有段的所有末端的元素 (x,y,i) 的向量,其中 x,y 表示末端的坐标,i 表示末端的索引(例如,2*段索引和 2*segment index + 1 表示段的两端)。

2) 使用 (x,y) 上的字典顺序对向量进行排序

3) 扫描向量,具有完全相同坐标的点在向量中是连续的(通过索引 i 可以检索它们对应的线段末端)

我正在使用这种算法来合并 3D 网格中的顶点,它简单且非常快,比使用散列图或集合快得多(在几秒钟内检测到大至 1000 万点的点集中的重复项)。

【讨论】:

    【解决方案2】:

    您的问题相当于在数组中查找重复项。在一般情况下,这个问题不能在 O(N) 时间和 0(1) 空间内解决。您可以按照建议使用排序来获得 O(N log N) 复杂度,或者使用数据结构。要在 general 案例中查找重复项,您可以查看 this 讨论。对于特殊情况,当一个大小为 n 的数组包含范围为 0,...n-1 的元素时,存在 O(N) 时间和 0(1) 空间解决方案,这使得使用关于元素可以用作索引的事实,请参阅this 帖子。

    但是,如果您仍然只谈论 10 个元素,那么即使是二次循环也不会造成太大影响。如果时间真的很关键,无论如何你都应该对这两种方法进行基准测试,而不是猜测。问题是没有人能告诉你哪一个在你的机器上只用 10 个元素会更快,因为纯复杂度类只对 large N 很重要。对于小 N,O(N^2) 算法可以比 O(N log n) 算法快得多。此外,除了内存分配、缓存效率和其他任何因素之外。所以,我的建议是:如果你真的关心速度,要么进行基准测试,否则就不要打扰。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 2020-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      相关资源
      最近更新 更多