【问题标题】:How to use BinarySearch for List<T>如何对 List<T> 使用 BinarySearch
【发布时间】:2011-06-23 07:15:09
【问题描述】:

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

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

众所周知,在使用 BinarySearch 之前,应该使用适当的 IComparer 对列表进行排序。但随后:要搜索列表,您必须提供 T 项。当人们习惯于根据这些项目的属性(即使用 Linq 或委托/谓词)搜索列表中的项目时,这是相当出乎意料的。因为当我已经有了我的 T 件时,我就不必搜索它了!

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

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

我的问题是:

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

您认为可以在 BinarySearch 中使用 Linq 样式搜索而无需先创建虚拟 T 项吗?

【问题讨论】:

    标签: c# list binary-search


    【解决方案1】:

    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 的包装器,但它仅适用于特定的 T(使用无参数构造函数等)。

    【讨论】:

    • 为什么这只适用于特定的 T,有任何相关文档吗?
    • 您不能(实际上)为所有实体提供一种通用的创建方法。你有不同数量的构造函数参数的类——你会自动选择哪一个?您将如何自动提供参数?对于可以限制的结构和无参数类来说,这很容易。在这方面,(恕我直言)简单地创建一个虚拟 T 更容易 - 因为 T 可以是任何东西。
    • 也许它有助于使用通用语法'where T : Basetype'并且包装器可以使用Basetype的构造函数?
    • 并且像这样限制通用参数将只允许特定的 Ts(正如我之前所说的) - 只允许 Basetype 的后代。关键是您必须在代码中为您想要使用的每个 BaseType 创建 T。
    【解决方案2】:

    实际上,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);
    }
    

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

    显然,当您使用原始比较器的子集时,您无法确定找到单个索引。所以这些方法返回一个二分查找的下界。

    【讨论】:

    • 添加了一点解释。 (否则会显得题外话...)
    猜你喜欢
    • 1970-01-01
    • 2011-02-03
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    相关资源
    最近更新 更多