以下是用例:
DateTime
类型的排序列表,粒度以毫秒为单位DateTime
,满足提供的predicate
委托我们目前正在做什么,自定义二进制搜索如下?
public static int BinaryLastOrDefault<T>(this IList<T> list, Predicate<T> predicate)
{
var lower = 0;
var upper = list.Count - 1;
while (lower < upper)
{
var mid = lower + ((upper - lower + 1) / 2);
if (predicate(list[mid]))
{
lower = mid;
}
else
{
upper = mid - 1;
}
}
if (lower >= list.Count) return -1;
return !predicate(list[lower]) ? -1 : lower;
}
我可以使用字典使其变为O(1)吗?
以下是我正在考虑的选项
Dictionary<int,SortedDictionary<DateTime,int>>
之类的数据结构36 million / 60 K = 600
SortedDictionary
,其中键为DateTime值,原始索引为值,因此如果需要,则可以枚举数据找到最接近的索引在我的理解中,此实现将使搜索比上面详细介绍的二进制搜索快得多,因为将大大减少搜索到的数据。任何建议都可以做得更多,以进一步缩短搜索时间,从而进一步改善算法,我可以分别为各种独立呼叫尝试“并行”选项
答案 0 :(得分:1)
我使用List<T>
的本机BinarySearch
方法进行了一些性能测试。查找最接近的DateTime
的逻辑如下所示:
public static DateTime GetNearest(List<DateTime> source, DateTime date)
{
var index = source.BinarySearch(date);
if (index >= 0) return source[index];
index = ~index;
if (index == 0) return source[0];
if (index == source.Count) return source[source.Count - 1];
var d1 = source[index - 1];
var d2 = source[index];
return (date - d1 < d2 - date) ? d1 : d2;
}
我创建了一个随机列表,其中包含1,000,000个排序日期,从最小到最大的时间跨度为10小时。然后,我创建了一个大小相等的列表,其中包含未排序的随机日期以进行搜索,覆盖的时间跨度略长。然后将内部版本更改为Release并开始测试。结果表明,仅使用相对较慢的机器的单个内核,就可以在不到一秒钟的时间内完成80万次搜索。
然后,我通过搜索包含1,000,000个元素的List<(DateTime, object)>
来增加测试的复杂性,因此每个比较都需要对dateSelector
函数进行两次额外的调用,该函数返回DateTime
属性每个ValueTuple
中的每个。
结果:每秒每个线程350,000次搜索。
我通过使用引用类型作为元素,并向List<Tuple<DateTime, object>>
填充了1,000,000个元组,进一步增加了复杂性。性能仍然相当不错:每秒每线程270,000次搜索。
我的结论是BinarySearch
方法快如闪电,如果发现它是应用程序的瓶颈,那将是令人惊讶的事情。