是否可以有效地计数与数字线上的单个点P重叠的线段的数量

Is it possible to efficiently count the number of line segments that overlap a single point P on a number line?

本文关键字:单个点 重叠 数字 有效地 是否      更新时间:2023-10-16

是否可以有效地计算与数字线上的单个点P重叠的线段数量?

所有线段都位于一条数字线上(这是一个1-D世界,而不是3-D世界)。

每个线段具有起始坐标X1和结束坐标X2

示例:

Line segment A spans from X1==1 to X2==3
Line segment B spans from X1==2 to X2==4
Line segment C spans from X1==3 to X2==5
Line segment D spans from X1==1 to X2==4
----------------------------------------
Ex1: Line segments that overlap point P==2: A,B and D   >>> overlap count==3.
Ex2: Line segments that overlap point P==7: None        >>> overlap count==0.
Ex3: Line segments that overlap point P==3: A,B,C and D >>> overlap count==4.

当然,如果只有4个线段,那么代码很简单。然而,如果有一个由4亿条线段组成的巨大空间数据库,那么搜索速度非常慢。

是否有任何算法可以有效地搜索线段列表中的重叠总数?

到目前为止我正在查看的内容

  • 关于空间索引搜索算法的文章
  • 间隔树(看起来很有前途)
  • 分段树(看起来很有前景)
  • R树

如果按起始值对列表进行排序,然后再按长度(对于相同的起始值)进行排序,则最终得到高效算法的根。

sort the list by starting value
for the same starting value, sort by length (longest first)

然后,当你需要与给定点p重叠的线段数量时:

for a given value p
find the points in the list with starting value <= p (binary search - fast)
for each starting value, start with the longest length
if it spans the point of interest, increment counter
if not, go to the next smaller start value
keep going until you have reached the smallest starting value

它并不完美,但比搜索10M个点要好得多(尽管最初的排序显然需要一些时间。但你只需要做一次)。

在单个数组中对查询点和区间端点进行越来越多的排序;对于每个点,保留一个标志,告诉它是间隔开始、间隔结束还是查询。

将计数器初始化为零并扫描列表。启动会增加计数器;末端使其减小;查询通过读取计数器来知道重叠间隔的数量。

时间(N+M)。如果可以使用特殊排序,则为对数(N+M。


如果不允许对查询点进行排序,只需对间隔端点进行排序。在单个线性扫描中,可以计算每个端点之后的重叠数量。

对于给定的查询点,您可以通过二分搜索找到相关的端点,从而获得重叠计数。

M个区间和N个查询点的M.Log(M)+N.Log(M)。


如果不允许对间隔进行排序,只需对查询点进行排序即可。

依次处理每个区间,通过二分搜索找到它重叠的第一个查询点,并增加它重叠的所有查询点的计数器。

N.Log(N)+M.Log(N)+O,其中O是间隔/查询重叠的总数。


如果根本不允许排序,请针对每个间隔对每个查询进行详尽的测试,N.M.

看看区间树或分段树可以帮助解决这类问题。这个答案有一些很好的例子来说明这些技术是如何帮助你的。

首先要意识到,你不能比O(N)做得更好,因为你需要至少看一次每个线段。(其中N=线段数量)

让我们有一个数组Line_segments_at,它存储通过每个点的线段数。

首先,我们需要将此数组初始化为0。然后,当我们看第i个线段时,我们需要做:

for(int j=x1[i];j<=x2[i];j++)
 Line_segments_at[j]++;

对于每个查询点k,我们可以简单地将结果返回为Line_segments_at[k]。