我有一组配对数字,需要有效地找到包含给定值的对的集合。
给出数字对的以下表示
public class Line
{
public double Start { get; set; } //is always < end
public double End { get; set; }
}
垂直红线是交叉标准(只是一个简单的数字,如10.123)
我正在寻找一种有效的算法,它只返回与红色相交的黑线,基于这样的假设:搜索执行的频率大于Line
添加到集合的频率。 (显然假设集合很大)
到目前为止,我不太理想的解决方案是
Start
排序,另一个按End
答案 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
}