如何使用BinarySearch for List <t> </t>

时间:2011-02-08 08:57:00

标签: c# list binary-search

让我们从List BinarySearch的重载开始:

public int BinarySearch(T item, IComparer<T> comparer);

众所周知,在使用BinarySearch之前,应使用适当的IComparer对列表进行排序。但是:要搜索列表,您必须提供T项。当使用一个基于这些项的属性(即使用Linq或delegates /谓词)来搜索列表中的项时,这是相当意外的。因为当我已经拥有我的T项时,我不必搜索它!

现在我在C#中实现了C ++代码,看到C ++程序员在他的代码中到处使用C ++样式二进制搜索,如下所示。首先,他制作了一个新的T项目并给了这个T项目他正在寻找的属性。然后他用它搜索列表,找到列表中具有相同属性的项目的索引。当然,C ++比较器适用于这些属性。

所以这是在List中查找项目的一种完全不同的方式。 BinarySearch创建一个虚拟 T项,并搜索一个索引,用它可以检索列表中的 real T项。从Linq的角度来看,这感觉不自然。

我的问题是:

我是否正确描述了BinarySearch背后的想法?

您是否认为可以在不使用虚拟T项目的情况下使用Linq样式搜索BinarySearch?

2 个答案:

答案 0 :(得分:5)

Did I give a correct description of the idea behind BinarySearch?
是。

Do you think it is possible to use a Linq style search with BinarySearch without making a dummy T item first?
不是它的当前形式。您可以使用一个为您创建虚拟T的包装器,它只适用于特定的Ts,但是(使用无参数构造函数等)。

答案 1 :(得分:0)

实际上,LINQ中没有类似内容,但您可以构建自己的扩展。 此示例允许您不传递虚拟项目,但仅传递原始比较器中使用的属性:

public static int FindFirstIndexGreaterThanOrEqualTo<TElement, TKey>(
                this IList<TElement> keySortedCollection,
                TKey key,
                Func<TElement, TKey> keySelector,
                IComparer<TKey> keyComparer)
{
    int begin = 0;
    int end = keySortedCollection.Count;
    while (end > begin)
    {
        int index = (begin + end) / 2;
        TElement el = keySortedCollection[index];
        TKey currElKey = keySelector(el);
        if (keyComparer.Compare(currElKey, key) >= 0)
            end = index;
        else
            begin = index + 1;
    }
    return end;
}

public static int FindFirstIndexGreaterThanOrEqualTo<TElement, TKey>(
                this IList<TElement> keySortedCollection,
                TKey key,
                Func<TElement, TKey> keySelector)
{
    return FindFirstIndexGreaterThanOrEqualTo(keySortedCollection,
                                               key,
                                               keySelector,
                                               Comparer<TKey>.Default);
}

使用这些方法,您可以进行比较,该比较是您最初用于对集合进行排序的一个子集。

显然,当您使用原始比较器的子集时,您无法确定找到单个索引。因此,这些方法返回较低的二进制搜索范围。