为什么有List .BinarySearch(…)?

我正在看List,我看到一个带有一些重载的BinarySearch方法,我不禁想知道在List中有这样的方法是否有意义?

除非列表已排序,否则为什么我要进行二进制搜索? 如果列表没有排序,调用该方法只会浪费CPU时间。 在List上使用该方法有什么意义?

排序和搜索是列表上的两个非常常见的操作。 通过不在常规列表上提供二进制搜索来限制开发人员的选项是不友好的。

图书馆设计需要妥协 – .NET设计人员选择在两个arrays上提供二进制搜索function和C#中的列表,因为他们可能觉得(就像我这样)这些是有用且常见的操作,选择使用它们的程序员理解他们的先决条件(在列表被命令之前),在调用它们之前。

使用Sort()重载之一对List进行排序很容易。 如果您觉得需要一个gaurantees排序的不变量,您可以使用SortedListSortedSet

我注意到除了其他正确答案之外,二进制搜索难以正确编写。 有很多极端情况和一些棘手的整数运算。 由于二进制搜索显然是对排序列表的常见操作,因此BCL团队通过正确编写二进制搜索算法而不是鼓励客户编写自己的二进制搜索算法,为世界提供服务; 大量这些客户撰写的算法都是错误的。

BinarySearch仅对已排序的List有意义,就像IList.Add仅对具有IsReadOnly = falseIList有意义。 这很麻烦,但它只是需要处理的事情:有时functionX取决于标准Y.Y并不总是正确的事实并不会使X无用。

现在,在看来,.NET没有针对任何 IList实现的一般 SortBinarySearch方法(例如,作为扩展方法),这令人沮丧。 如果是这样,我们可以轻松地对任何非只读集合中的项目进行排序搜索,从而提供随机访问。

然后,你可以随时编写自己的(或复制别人的 )。

其他人指出BinarySearch在排序的List上非常有用。 但它并不真正属于List ,因为任何具有C ++ STL经验的人都会立即认出来。

随着最近的C#语言开发,定义排序列表的概念(例如, ISortedList : IList )并将BinarySearch (等人)定义为该接口的扩展方法更有意义。 这是一种更清洁,更正交的设计。

我已经开始将其作为Nito.Linq库的一部分。 我预计第一个稳定版本会在几个月内发布。

是,但List也有Sort()方法,所以你可以在BinarySearch之前调用它。

我同意在未排序的列表中调用BinarySearch是完全愚蠢的,但如果您知道您的大型列表已排序,则它是完美的。

我在检查流中的项是否存在于(或多或少)100,000个或更多项的静态列表时使用过它。

二进制搜索列表的ORDERS比执行list更快。找到,比数据库查找快许多个数量级。

我有道理,我很高兴(如果不是这样的话,那就不是实施它的火箭科学)。

搜索和排序是算法原语。 标准库具有快速可靠的实现是有帮助的。 否则,开发人员会浪费时间重新发明轮子。

但是,在.NET Framework的情况下,遗憾的是,算法的具体选择恰好使它们不像它们那样有用。 在某些情况下,他们的行为没有定义:

  1. List.BinarySearch如果List包含多个具有相同值的元素,则该方法仅返回其中一个出现,并且它可能返回任何一个出现, 不一定是第一个出现

  2. List此实现执行不稳定的排序; 也就是说,如果两个元素相等,则可能不会保留它们的顺序 。 相反,稳定的排序保留了相等元素的顺序。

这是一种耻辱,因为确实性算法同样快,并且这些算法作为构建块更有用。 值得注意的是,Python,Ruby和Go中的二进制搜索算法都找到了第一个匹配元素。

也许另一点是数组可以同样未排序。 所以理论上,在arrays上使用BinarySearch也可能是无效的。

但是,与更高级别语言的所有function一样,它们需要由具有理性和理解数据的人员应用,否则它们将失败。 当然,可以应用一些交叉检查,我们可以有一个标记“IsSorted”,否则它会在二进制搜索上失败,但…..

一些伪代码:

 if List is sorted use the BinarySearch method else if List is not sorted and you think sorting it is "waste of CPU time" use a different algorithm that is more suitable and efficient