如何在IList ?]上执行二进制搜索? 简单的问题-给定IList<T>,如何在不自己编写方法的情况下以及不将数据复制到具有内置二进制搜索支持的类型的情况下执行二进制搜索。我当前的状态如下。 [List<T>.BinarySearch()不是IList<T>的成员 ArrayList.Adapter()的ArrayList.Adapter()方法没有与此等效的方法>> [List<T>不继承自IList<T>,因此无法使用IList 我倾向于认为内置方法不可能实现,但是我不能相信BCL / FCL中缺少这种基本方法。 如果不可能,谁可以为ArrayList.Adapter()提供最短,最快,最聪明或最漂亮的二进制搜索实现? UPDATE 我们都知道,在使用二进制搜索之前,必须对列表进行排序,因此可以假定它是。但是我假设(但未验证)排序是否存在相同问题-如何排序IList<T>? 结论 [[0]似乎没有内置的二进制搜索。可以使用IList<T>和IList<T> LINQ方法进行搜索和排序,但是它会带来性能上的损失。自己实现(作为扩展方法)似乎可以做的最好。 简单的问题-给定一个IList ,您如何在不自己编写方法的情况下执行二进制搜索,又如何在不支持内置二进制搜索的情况下将数据复制到类型中。我当前的... 我怀疑在.NET中有这样一种通用的二进制搜索方法,除了在某些基类中存在(但显然不在接口中),所以这是我的通用目的。 First() 当然,这是根据比较器将使用的相同规则,对有关列表进行了排序。 我喜欢扩展方法的解决方案。但是,应注意一些警告。 这实际上是乔恩·本特利(Jon Bentley)在他的《 Programming Pearls》一书中的实现,它遭受了一个数值溢出的错误的困扰,该错误在20年左右的时间里未被发现。如果IList中有大量项目,则(upper + lower)可能会溢出Int32。一个解决方案是使用减法来略微不同地进行中间计算。中=下+(上-下)/ 2; [Bentley还在Programming Pearls中警告说,虽然二进制搜索算法于1946年发布,但第一个正确的实现直到1962年才发布。 OrderBy() 这是我的Lasse代码版本。我发现能够使用lambda表达式执行搜索很有用。在对象列表中搜索时,它仅允许传递用于排序的键。使用IComparer的实现是从这个琐碎的派生而来的。 我也想在找不到匹配项时返回〜lower。 Array.BinarySearch做到了这一点,它使您可以知道要搜索的项目应插入到哪里,以保持顺序。 public static Int32 BinarySearchIndexOf<T>(this IList<T> list, T value, IComparer<T> comparer = null) { if (list == null) throw new ArgumentNullException(nameof(list)); comparer = comparer ?? Comparer<T>.Default; Int32 lower = 0; Int32 upper = list.Count - 1; while (lower <= upper) { Int32 middle = lower + (upper - lower) / 2; Int32 comparisonResult = comparer.Compare(value, list[middle]); if (comparisonResult == 0) return middle; else if (comparisonResult < 0) upper = middle - 1; else lower = middle + 1; } return ~lower; } 一段时间以来,我一直在努力解决这个问题。特别是在MSDN中指定的边缘情况的返回值:http://en.wikipedia.org/wiki/Binary_search#Numerical_difficulties 我现在已经从.NET 4.0复制了ArraySortHelper.InternalBinarySearch()并出于各种原因做出了自己的选择。 用法: /// <summary> /// Performs a binary search on the specified collection. /// </summary> /// <typeparam name="TItem">The type of the item.</typeparam> /// <typeparam name="TSearch">The type of the searched item.</typeparam> /// <param name="list">The list to be searched.</param> /// <param name="value">The value to search for.</param> /// <param name="comparer">The comparer that is used to compare the value /// with the list items.</param> /// <returns></returns> public static int BinarySearch<TItem, TSearch>(this IList<TItem> list, TSearch value, Func<TSearch, TItem, int> comparer) { if (list == null) { throw new ArgumentNullException("list"); } if (comparer == null) { throw new ArgumentNullException("comparer"); } int lower = 0; int upper = list.Count - 1; while (lower <= upper) { int middle = lower + (upper - lower) / 2; int comparisonResult = comparer(value, list[middle]); if (comparisonResult < 0) { upper = middle - 1; } else if (comparisonResult > 0) { lower = middle + 1; } else { return middle; } } return ~lower; } /// <summary> /// Performs a binary search on the specified collection. /// </summary> /// <typeparam name="TItem">The type of the item.</typeparam> /// <param name="list">The list to be searched.</param> /// <param name="value">The value to search for.</param> /// <returns></returns> public static int BinarySearch<TItem>(this IList<TItem> list, TItem value) { return BinarySearch(list, value, Comparer<TItem>.Default); } /// <summary> /// Performs a binary search on the specified collection. /// </summary> /// <typeparam name="TItem">The type of the item.</typeparam> /// <param name="list">The list to be searched.</param> /// <param name="value">The value to search for.</param> /// <param name="comparer">The comparer that is used to compare the value /// with the list items.</param> /// <returns></returns> public static int BinarySearch<TItem>(this IList<TItem> list, TItem value, IComparer<TItem> comparer) { return list.BinarySearch(value, comparer.Compare); } 这应该适用于所有.NET类型。到目前为止,我已经尝试过int,long和double。 实施: http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx 单元测试: var numbers = new List<int>() { ... }; var items = new List<FooInt>() { ... }; int result1 = numbers.BinarySearchIndexOf(5); int result2 = items.BinarySearchIndexOfBy(foo => foo.bar, 5); 我只是从我自己的代码中剪了出来,所以如果不能立即使用请发表评论。 希望至少可以根据MSDN规范,通过可行的解决方案一劳永逸地解决该问题。 [二进制搜索public static class BinarySearchUtils { public static int BinarySearchIndexOf<TItem>(this IList<TItem> list, TItem targetValue, IComparer<TItem> comparer = null) { Func<TItem, TItem, int> compareFunc = comparer != null ? comparer.Compare : (Func<TItem, TItem, int>) Comparer<TItem>.Default.Compare; int index = BinarySearchIndexOfBy(list, compareFunc, targetValue); return index; } public static int BinarySearchIndexOfBy<TItem, TValue>(this IList<TItem> list, Func<TItem, TValue, int> comparer, TValue value) { if (list == null) throw new ArgumentNullException("list"); if (comparer == null) throw new ArgumentNullException("comparer"); if (list.Count == 0) return -1; // Implementation below copied largely from .NET4 ArraySortHelper.InternalBinarySearch() int lo = 0; int hi = list.Count - 1; while (lo <= hi) { int i = lo + ((hi - lo) >> 1); int order = comparer(list[i], value); if (order == 0) return i; if (order < 0) { lo = i + 1; } else { hi = i - 1; } } return ~lo; } } 时会遇到一些问题,首先,就像您提到的那样,[TestFixture] public class BinarySearchUtilsTest { [Test] public void BinarySearchReturnValueByMsdnSpecification() { var numbers = new List<int>() { 1, 3 }; // Following the MSDN documentation for List<T>.BinarySearch: // http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx // The zero-based index of item in the sorted List(Of T), if item is found; int index = numbers.BinarySearchIndexOf(1); Assert.AreEqual(0, index); index = numbers.BinarySearchIndexOf(3); Assert.AreEqual(1, index); // otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item index = numbers.BinarySearchIndexOf(0); Assert.AreEqual(~0, index); index = numbers.BinarySearchIndexOf(2); Assert.AreEqual(~1, index); // or, if there is no larger element, the bitwise complement of Count. index = numbers.BinarySearchIndexOf(4); Assert.AreEqual(~numbers.Count, index); } } 上的IList<T>方法不是BinarySearch接口的成员。其次,您无法在搜索之前对列表进行排序(必须进行二进制搜索才能工作)。 我认为您最好的选择是创建一个新的List<T>,对其进行排序,然后进行搜索。它并不完美,但是如果您有IList<T>,则没有太多选择。 [请注意,下面的Antoine提供的实现中存在一个错误:当搜索大于列表中任何项的项时。返回值应该是较低的而不是中间的。反编译方法ArraySortHelper.InternalBinarySearch(mscorlib)以查看框架实现。 如果您需要现成的实现来对List<T>,IList<T> IList<T>(在Wintellect's Power Collections中进行二进制搜索: has one 您可以使用Algorithms.cs。如果要使用自定义比较器,请使用/// <summary> /// Searches a sorted list for an item via binary search. The list must be sorted /// by the natural ordering of the type (it's implementation of IComparable&lt;T&gt;). /// </summary> /// <param name="list">The sorted list to search.</param> /// <param name="item">The item to search for.</param> /// <param name="index">Returns the first index at which the item can be found. If the return /// value is zero, indicating that <paramref name="item"/> was not present in the list, then this /// returns the index at which <paramref name="item"/> could be inserted to maintain the sorted /// order of the list.</param> /// <returns>The number of items equal to <paramref name="item"/> that appear in the list.</returns> public static int BinarySearch<T>(IList<T> list, T item, out int index) where T: IComparable<T> { // ... } 。请查看此MSDN List<T>.BinarySearch(T item)了解更多详细信息。 请记住,对于某些列表实现,二进制搜索可能效率很低。例如,对于链表,如果正确实现,则为O(n);如果天真的实现,则为O(n log n)。 如果可以使用.NET 3.5,则可以使用Linq扩展方法中的构建: List<T>.BinarySearch(T item, IComparer<T> comparer) 但是,这实际上是解决安德鲁·哈尔(Andrew Hare)解决方案的方式略有不同,并且仅当您多次从同一有序列表中进行搜索时才有用。 请注意,虽然List和IList没有BinarySearch方法,但SortedList有。

问题描述 投票:37回答:11
简单的问题-给定IList<T>,如何在不自己编写方法的情况下以及不将数据复制到具有内置二进制搜索支持的类型的情况下执行二进制搜索。我当前的状态如下。

    [List<T>.BinarySearch()不是IList<T>的成员
  • ArrayList.Adapter()ArrayList.Adapter()方法没有与此等效的方法>>
  • [List<T>不继承自IList<T>,因此无法使用IList
  • 我倾向于认为内置方法不可能实现,但是我不能相信BCL / FCL中缺少这种基本方法。
  • 如果不可能,谁可以为ArrayList.Adapter()提供最短,最快,最聪明或最漂亮的二进制搜索实现?

    UPDATE

我们都知道,在使用二进制搜索之前,必须对列表进行排序,因此可以假定它是。但是我假设(但未验证)排序是否存在相同问题-如何排序IList<T>

结论

[[0]似乎没有内置的二进制搜索。可以使用IList<T>IList<T> LINQ方法进行搜索和排序,但是它会带来性能上的损失。自己实现(作为扩展方法)似乎可以做的最好。

简单的问题-给定一个IList

,您如何在不自己编写方法的情况下执行二进制搜索,又如何在不支持内置二进制搜索的情况下将数据复制到类型中。我当前的...

.net generics list interface binary-search
11个回答
32
投票
我怀疑在.NET中有这样一种通用的二进制搜索方法,除了在某些基类中存在(但显然不在接口中),所以这是我的通用目的。

First()

当然,这是根据比较器将使用的相同规则,对有关列表进行了排序。

-1
投票
如果可以使用.NET 3.5,则可以使用Linq扩展方法中的构建:

List<T>.BinarySearch(T item, IComparer<T> comparer)


-3
投票
请注意,虽然List和IList没有BinarySearch方法,但SortedList有。

31
投票
我喜欢扩展方法的解决方案。但是,应注意一些警告。

这实际上是乔恩·本特利(Jon Bentley)在他的《 Programming Pearls》一书中的实现,它遭受了一个数值溢出的错误的困扰,该错误在20年左右的时间里未被发现。如果IList中有大量项目,则(upper + lower)可能会溢出Int32。一个解决方案是使用减法来略微不同地进行中间计算。中=下+(上-下)/ 2;


29
投票
这是我的Lasse代码版本。我发现能够使用lambda表达式执行搜索很有用。在对象列表中搜索时,它仅允许传递用于排序的键。使用IComparer的实现是从这个琐碎的派生而来的。

我也想在找不到匹配项时返回〜lower。 Array.BinarySearch做到了这一点,它使您可以知道要搜索的项目应插入到哪里,以保持顺序。


5
投票
一段时间以来,我一直在努力解决这个问题。特别是在MSDN中指定的边缘情况的返回值:http://en.wikipedia.org/wiki/Binary_search#Numerical_difficulties

我现在已经从.NET 4.0复制了ArraySortHelper.InternalBinarySearch()并出于各种原因做出了自己的选择。


4
投票
[二进制搜索public static class BinarySearchUtils { public static int BinarySearchIndexOf<TItem>(this IList<TItem> list, TItem targetValue, IComparer<TItem> comparer = null) { Func<TItem, TItem, int> compareFunc = comparer != null ? comparer.Compare : (Func<TItem, TItem, int>) Comparer<TItem>.Default.Compare; int index = BinarySearchIndexOfBy(list, compareFunc, targetValue); return index; } public static int BinarySearchIndexOfBy<TItem, TValue>(this IList<TItem> list, Func<TItem, TValue, int> comparer, TValue value) { if (list == null) throw new ArgumentNullException("list"); if (comparer == null) throw new ArgumentNullException("comparer"); if (list.Count == 0) return -1; // Implementation below copied largely from .NET4 ArraySortHelper.InternalBinarySearch() int lo = 0; int hi = list.Count - 1; while (lo <= hi) { int i = lo + ((hi - lo) >> 1); int order = comparer(list[i], value); if (order == 0) return i; if (order < 0) { lo = i + 1; } else { hi = i - 1; } } return ~lo; } } 时会遇到一些问题,首先,就像您提到的那样,[TestFixture] public class BinarySearchUtilsTest { [Test] public void BinarySearchReturnValueByMsdnSpecification() { var numbers = new List<int>() { 1, 3 }; // Following the MSDN documentation for List<T>.BinarySearch: // http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx // The zero-based index of item in the sorted List(Of T), if item is found; int index = numbers.BinarySearchIndexOf(1); Assert.AreEqual(0, index); index = numbers.BinarySearchIndexOf(3); Assert.AreEqual(1, index); // otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item index = numbers.BinarySearchIndexOf(0); Assert.AreEqual(~0, index); index = numbers.BinarySearchIndexOf(2); Assert.AreEqual(~1, index); // or, if there is no larger element, the bitwise complement of Count. index = numbers.BinarySearchIndexOf(4); Assert.AreEqual(~numbers.Count, index); } } 上的IList<T>方法不是BinarySearch接口的成员。其次,您无法在搜索之前对列表进行排序(必须进行二进制搜索才能工作)。

我认为您最好的选择是创建一个新的List<T>,对其进行排序,然后进行搜索。它并不完美,但是如果您有IList<T>,则没有太多选择。


3
投票
[请注意,下面的Antoine提供的实现中存在一个错误:当搜索大于列表中任何项的项时。返回值应该是较低的而不是中间的。反编译方法ArraySortHelper.InternalBinarySearch(mscorlib)以查看框架实现。

2
投票
如果您需要现成的实现来对List<T>IList<T> IList<T>(在Wintellect's Power Collections中进行二进制搜索:

has one


2
投票
您可以使用Algorithms.cs。如果要使用自定义比较器,请使用/// <summary> /// Searches a sorted list for an item via binary search. The list must be sorted /// by the natural ordering of the type (it's implementation of IComparable&lt;T&gt;). /// </summary> /// <param name="list">The sorted list to search.</param> /// <param name="item">The item to search for.</param> /// <param name="index">Returns the first index at which the item can be found. If the return /// value is zero, indicating that <paramref name="item"/> was not present in the list, then this /// returns the index at which <paramref name="item"/> could be inserted to maintain the sorted /// order of the list.</param> /// <returns>The number of items equal to <paramref name="item"/> that appear in the list.</returns> public static int BinarySearch<T>(IList<T> list, T item, out int index) where T: IComparable<T> { // ... } 。请查看此MSDN List<T>.BinarySearch(T item)了解更多详细信息。

-1
投票
请记住,对于某些列表实现,二进制搜索可能效率很低。例如,对于链表,如果正确实现,则为O(n);如果天真的实现,则为O(n log n)。
© www.soinside.com 2019 - 2024. All rights reserved.