用于有界线集合的交集的有效算法

时间:2017-11-18 23:33:43

标签: c# algorithm math

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

给出数字对的以下表示

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

Lines的集合可以像下面那样用视觉布局(黑线) enter image description here

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

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

到目前为止,我不太理想的解决方案是

  1. 将创建的行插入两个已排序的列表中。一个按Start排序,另一个按End
  2. 排序
  3. 二进制搜索起始有序列表,以查找起始大于交叉条件的第一行的索引。 (理论上所有包括和在此指数之后的线都是非交叉的)
  4. 在(2)中为最终有序列表重复类似的逻辑
  5. 比较索引并选择要解析的剩余迭代次数最少的列表
  6. 手动寻找交叉点迭代所选列表的其余部分

2 个答案:

答案 0 :(得分:2)

您的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?

答案 1 :(得分:0)

这可能是由两个平行的搜索者完成的,但是......
由于您已经管理了两个列表,请尝试以下方法:

搜索第一个.Start值&gt; 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值&gt; 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
}