如何对 IList执行二分查找?
简单的问题 - 给定一个 IList
List
不是.BinarySearch() IList
的成员- 没有与
ArrayList.Adapter()
方法List
< /code> IList
不会从IList
继承,因此使用ArrayList.Adapter()
是不可能的,
我倾向于认为这是使用内置方法是不可能的,但我无法相信 BCL/FCL 中缺少这样的基本方法。
如果不可能,谁能为 IList
提供最短、最快、最智能或最漂亮的二分搜索实现?
更新
我们都知道在使用二分搜索之前必须对列表进行排序,因此您可以假设它是这样的。 但我假设(但没有验证)排序也有同样的问题 - 如何排序 IList
?
结论
IList
似乎没有内置的二分搜索。 可以使用 First()
和 OrderBy()
LINQ 方法进行搜索和排序,但可能会影响性能。 自己实现它(作为扩展方法)似乎是您能做的最好的事情。
Simple question - given an IList<T>
how do you perform a binary search without writing the method yourself and without copying the data to a type with build-in binary search support. My current status is the following.
List<T>.BinarySearch()
is not a member ofIList<T>
- There is no equivalent of the
ArrayList.Adapter()
method forList<T>
IList<T>
does not inherit fromIList
, hence usingArrayList.Adapter()
is not possible
I tend to believe that is not possible with build-in methods, but I cannot believe that such a basic method is missing from the BCL/FCL.
If it is not possible, who can give the shortest, fastest, smartest, or most beatiful binary search implementation for IList<T>
?
UPDATE
We all know that a list must be sorted before using binary search, hence you can assume that it is. But I assume (but did not verify) it is the same problem with sort - how do you sort IList<T>
?
CONCLUSION
There seems to be no build-in binary search for IList<T>
. One can use First()
and OrderBy()
LINQ methods to search and sort, but it will likly have a performance hit. Implementing it yourself (as an extension method) seems the best you can do.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
我怀疑 .NET 中是否存在这样的通用二分搜索方法,除了某些基类中存在的方法(但显然不在接口中),所以这是我的通用二分搜索方法。
当然,这假设所讨论的列表已经根据比较器将使用的相同规则进行排序。
I doubt there is a general purpose binary search method in .NET like that, except for the one being present in some base classes (but apparently not in the interfaces), so here's my general purpose one.
This of course assumes that the list in question is already sorted, according to the same rules that the comparer will use.
这是我的 Lasse 代码版本。 我发现能够使用 lambda 表达式来执行搜索非常有用。 在对象列表中搜索时,它允许仅传递用于排序的键。 使用 IComparer 的实现基本上都是从这个实现派生的。
当没有找到匹配项时,我也喜欢返回~lower。 Array.BinarySearch 做到了这一点,它允许您知道您搜索的项目应该插入到哪里以保持顺序。
Here's my version of Lasse's code. I find it useful to be able to use a lambda expression to perform the search. When searching in a list of objects, it permits to pass only the key that was used to sort. Implementations that use IComparer are trivially derived from this one.
I also like to return ~lower when no match is found. Array.BinarySearch does it and it allows you to know where the item you searched for should be inserted in order to keep the ordering.
我喜欢使用扩展方法的解决方案。 然而,有一点警告是有必要的。
这实际上是 Jon Bentley 在他的《Programming Pearls》一书中的实现,它受到了数字溢出错误的影响,该错误在大约 20 年里未被发现。 如果 IList 中有大量项目,(upper+lower) 可能会溢出 Int32。 解决这个问题的方法是使用减法稍微不同地进行中间计算; 中 = 下 + (上 - 下) / 2;
Bentley 还在《Programming Pearls》中警告说,虽然二分搜索算法于 1946 年发布,但第一个正确的实现直到 1962 年才发布。
http://en.wikipedia.org/wiki/Binary_search#Numerical_difficulties
I like the solution with the extension method. However, a bit of warning is in order.
This is effectively Jon Bentley's implementation from his book Programming Pearls and it suffers modestly from a bug with numeric overflow that went undiscovered for 20 years or so. The (upper+lower) can overflow Int32 if you have a large number of items in the IList. A resolution to this is to do the middle calculation a bit differently using a subtraction instead; Middle = Lower + (Upper - Lower) / 2;
Bentley also warned in Programming Pearls that while the binary search algorithm was published in 1946 and the first correct implementation wasn't published until 1962.
http://en.wikipedia.org/wiki/Binary_search#Numerical_difficulties
一段时间以来,我一直在努力解决这个问题。 特别是 MSDN 中指定的边缘情况的返回值: http://msdn .microsoft.com/en-us/library/w4e7fxsh.aspx
我现在从 .NET 4.0 复制了 ArraySortHelper.InternalBinarySearch() 并出于各种原因制作了自己的风格。
用法:
这应该适用于所有 .NET 类型。 到目前为止我已经尝试过 int、long 和 double 了。
实现:
单元测试:
我刚刚从我自己的代码中删除了它,所以如果它不能开箱即用,请发表评论。
希望这能够一劳永逸地解决问题,至少根据 MSDN 规范。
I have been struggling with getting this right for some time now. In particular the return values for edge cases as specified in MSDN: http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx
I have now copied the ArraySortHelper.InternalBinarySearch() from .NET 4.0 and made my own flavor for various reasons.
Usage:
This should work with all .NET types. I have tried int, long and double so far.
Implementation:
Unit tests:
I just scissored this out from my own code, so please comment if it doesn't work out of the box.
Hope this settles the issue with a working implementation once and for all, at least according to MSDN specs.
对
IList
进行二进制搜索时,您将遇到几个问题,首先,就像您提到的那样,List上的
不是BinarySearch
方法是可行的。IList
接口的成员。 其次,您无法在搜索之前对列表进行排序(您必须这样做才能使二分搜索起作用)。我认为最好的选择是创建一个新的
List
,对其进行排序,然后进行搜索。 它并不完美,但如果您有IList
,您就不必有太多选择。You are going to have a couple of problems binary-searching an
IList<T>
, First ,like you mentioned, theBinarySearch
method on theList<T>
is not a member of theIList<T>
interface. Second, you have no way of sorting the list prior to searching (which you must do for a binary search to work).I think your best bet is to create a new
List<T>
, sort it, and then search. It's not perfect but you don't have to many options if you have anIList<T>
.请注意,Antoine 在下面提供的实现中存在一个错误:搜索大于列表中任何项目的项目时。 返回值应该是 ~lower 而不是 ~middle。 反编译方法ArraySortHelper.InternalBinarySearch(mscorlib)以查看框架实现。
Note that there is a bug in the implementation provided by Antoine below: when searching for an item greater than any in the list. The return value should be ~lower not ~middle. Decompile method ArraySortHelper.InternalBinarySearch (mscorlib) to see the framework implementation.
您可以使用
List.BinarySearch(T item)
。 如果您想使用自定义比较器,请使用List.BinarySearch(T item, IComparerComparer)
。 查看此 MSDN 链接更多细节。You can use
List<T>.BinarySearch(T item)
. If you want to use a custom comparer then useList<T>.BinarySearch(T item, IComparer<T> comparer)
. Take a look at this MSDN link for more details.如果您需要在
IList
上实现二分搜索的现成实现,Wintellect 的强大功能集合 有一个(在 <代码>Algorithms.cs):If you need a ready-made implementation for binary search on
IList<T>
s, Wintellect's Power Collections has one (inAlgorithms.cs
):请记住,对于某些列表实现来说,二分搜索可能效率很低。 例如,对于链表,如果你正确实现它,它是 O(n) ,如果你简单地实现它,它是 O(n log n) 。
Keep in mind that binary search can be quite inefficient for some list implementations. For example, for a linked list it is O(n) if you implement it correctly, and O(n log n) if you implement it naively.
如果您可以使用 .NET 3.5,则可以使用 Linq 扩展方法中的构建:
但是,这实际上只是 Andrew Hare 解决方案的一种稍微不同的方式,并且只有在您多次搜索同一内容时才真正有用。有序列表。
If you can use .NET 3.5, you can use the build in Linq extension methods:
However, this is really just a slightly different way of going about Andrew Hare's solution, and is only really helpful if you are searching multiple times off of the same ordered list.
请注意,虽然 List 和 IList 没有 BinarySearch 方法,但 SortedList 有。
Note that while List and IList do not have a BinarySearch method, SortedList does.