【问题标题】:Efficient algorithm for intersection of a collection of bounded lines有界线集合相交的高效算法
【发布时间】:2017-11-18 23:33:43
【问题描述】:

我有一组成对的数字,需要有效地找到包含给定值的成对集合。

给定以下数字对的表示形式

public class Line
{
    public double Start { get; set; } //is always < end
    public double End { get; set; }
}

Lines 的集合可以在视觉上像下面这样布局(黑线)

垂直的红线是相交标准(只是一个简单的数字,比如 10.123)

我正在寻找一种有效的算法,该算法仅返回与红色相交的黑线,假设搜索执行的频率大于 Line 添加到集合的频率。 (显然假设集合很大)

到目前为止,我的最佳解决方案是

  1. 在创建到两个排序列表时插入行。一个排序在Start,另一个排序在End
  2. 对起始有序列表进行二分搜索,以查找起始大于交集条件的第一行的索引。 (理论上,包括该索引和该索引之后的所有线都不相交)
  3. 对最终有序列表重复 (2) 中的类似逻辑
  4. 比较索引并选择剩余迭代次数最少的列表来解决
  5. 手动遍历所选列表的其余部分以查找交叉点

【问题讨论】:

  • lines.Where(l =&gt; l.Start &lt;= criteria &amp;&amp; l.End &gt;= criteria) 会不会太低效?还是我过于简单化了?
  • 这需要点击集合中的每个项目。
  • 根据有多少范围,将范围划分为范围桶(一个范围可以在多个范围桶中)可能会导致比二分查找更少的比较,并且可能更容易并行化跨度>
  • 也许你想要Interval tree
  • @dbc Ahh Interval Tree 完美地描述了我的确切问题,谢谢。我会找到一些实现并运行一些性能测试。它肯定比我的滚动解决方案更快。作为答案发布,我会接受。

标签: c# algorithm math


【解决方案1】:

您的Line 类代表 中的interval。您有大量这样的间隔,并且希望在比线性时间更好的时间内找到与某个点重叠的那些。

interval tree 是满足您要求的一种可能解决方案:

  • 查询需要O(log n + m)时间,其中n是区间总数,m是与找到的查询点的重叠数。
  • 构造需要O(n log n)
  • 存储需要O(n) 空间。

Codeplex 的示例实现(我尚未测试)。对于其他人,请参阅C# Interval tree class

要与相关结构segment tree 进行比较,请参阅What are the differences between segment trees, interval trees, binary indexed trees and range trees?

【讨论】:

    【解决方案2】:

    这可能应该通过两个并行搜索器来完成,但是...
    由于您已经管理了两个列表,请尝试以下操作:

    搜索第一个 .Start 值 > ValuePoint
    (超出此索引的所有值显然无效)

    int idx_start = Lines.FindIndex(x => x.Start > ValuePoint);
    

    按 [.End] 的值对列表进行排序
    鉴于您的列表已经排序,此排序永远不会是 O(n) 操作,
    应该平均到O((i) log (i)),其中i = Index 是找到的第一个值。
    当然,i 可能是= n

    EndComparer ecomp = new EndComparer();
    Lines.Sort(0, idx_start, eComp);
    

    EndComparer:

    public class EndComparer : IComparer<Lines>
    {
        public int Compare(Lines lineX, Lines lineY)
        {
            return lineX.End.CompareTo(lineY.End);
        }
    }
    

    然后找到第一个.End值>ValuePoint

    int idx_end = Lines.FindIndex(0, idx_start, x => x.End > ValuePoint);
    
    if (idx_end > -1)
    {
        //All values in the range [idx_end; idx_start] are valid
        //If idx_end = 0 then all pre-selected values are valid [0; idx_start]
    } else {
        //All value in the range are non valid
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-05
      • 2011-06-17
      • 1970-01-01
      • 2010-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-16
      相关资源
      最近更新 更多