我有一系列片段,它们的末端最多相互交叉。我想将这些段合并为折线。
是否有一种算法在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
但是第二个循环显然是二次的,所以我想知道是否有更好的算法来合并/连接/组合它们之间的一系列段。
答案 0 :(得分:1)
我严重怀疑O(n)方法是否存在。
这是一个O(n log(n))方法,用于检测具有完全相同坐标的分段末端。它使用"数据结构",但它是一个非常简单的(只是一个向量):
1)创建所有段的所有末端的元素(x,y,i)的向量,其中x,y表示极值的坐标,i表示极值的索引(例如,2 *段索引)和2 *段索引+ 1段的两个末端)。
2)在(x,y)
上按字典顺序对矢量进行排序3)扫描向量,具有完全相同坐标的点在向量中是连续的(对于索引i,您可以检索它们对应的段末端)
我正在使用此算法合并3D网格中的顶点,它简单而快速,比使用哈希映射或集合要快得多(在几秒内检测到点集中的重复点大到1000万点)。 / p>
答案 1 :(得分:0)
您的问题等同于在数组中查找重复项。在一般情况下,在O(N)时间和0(1)空间中不能解决该问题。您可以按照建议使用排序来使O(N log N)复杂,或使用数据结构。要查找常规案例中的重复项,您可以查看this讨论。对于特殊情况,当大小为n的数组包含范围0,... n-1中的元素时,有一个O(N)时间和0(1)空间解决方案,它使用可以将元素用作索引这一事实,请参阅this post。
然而,如果你只谈论大约10个元素,即使是二次循环也不会受到太大影响。如果时间真的至关重要,那么在任何情况下都应该对两种方法进行基准测试,而不是猜测。问题是,没有人可以告诉你哪一个在你的机器上只有10个元素会更快,因为纯复杂性类只对大N 变得重要。对于小N,O(N ^ 2)算法可以比O(N log n)算法快得多。此外,除了内存分配,缓存效率和其他任何其他功能。所以,我的建议是:如果你真的关心速度,要么是基准,要么如果你不关心,不要打扰。