2013-02-26 35 views
1

我有一个对象的数组A,每个对象都具有公共字段值(双),它具有0和1之间的随机双精度。A按此字段排序。我创建了double random = 0.25。现在我想从A中找到A [index] .Value> = random的第一个对象。我可以用int index = Array.BinarySearch()以某种方式执行此操作吗?自定义类型的二进制搜索数组

+0

听起来像是因为你希望*第一*的*不精确*匹配的项目,最二进制搜索算法可以做的是隔离“小足够“的范围让你迭代,但我可能会误解。 – 2013-02-26 19:59:10

+0

@AnthonyPegram你错了,二进制搜索正是他想要的,问题是他没有一个与数组相同类型的对象,他只是有他想要比较的值。逻辑上,二分查找可以工作,他可能无法使用二进制搜索的“Array”实现。 – Servy 2013-02-26 20:00:47

+0

@Servy,你可能是对的,我正在想这件事。在找到最初的比赛之后(即使是确切的),他必须继续寻找,直到他已经满意他是否已经发现了该比赛的第一次连续出现为止。我认为一旦发现任何匹配,典型的二进制搜索就会愉快地返回。 (我注意到,我在算法领域非常不称职,不是CS专业或者填补了这些空白)。 – 2013-02-26 20:06:49

回答

3

这里是BinarySearch,您可以使用一个实现。除了通常会被接受的其他参数之外,它还接受selector,它确定每个项目应该比较的实际对象,并且找到它的值接受该类型的值,而不是阵列。

public static int BinarySearch<TSource, TKey>(this IList<TSource> collection 
    , TKey item, Func<TSource, TKey> selector, Comparer<TKey> comparer = null) 
{ 
    return BinarySearch(collection, item, selector, comparer, 0, collection.Count); 
} 
private static int BinarySearch<TSource, TKey>(this IList<TSource> collection 
    , TKey item, Func<TSource, TKey> selector, Comparer<TKey> comparer 
    , int startIndex, int endIndex) 
{ 
    comparer = comparer ?? Comparer<TKey>.Default; 

    while (true) 
    { 
     if (startIndex == endIndex) 
     { 
      return startIndex; 
     } 

     int testIndex = startIndex + ((endIndex - startIndex)/2); 
     int comparision = comparer.Compare(selector(collection[testIndex]), item); 
     if (comparision > 0) 
     { 
      endIndex = testIndex; 
     } 
     else if (comparision == 0) 
     { 
      return testIndex; 
     } 
     else 
     { 
      startIndex = testIndex + 1; 
     } 
    } 
} 

要使用它很简单:

public class Foo 
{ 
    public double Value { get; set; } 
} 

private static void Main(string[] args) 
{ 
    Foo[] array = new Foo[5]; 
    //populate array with values 
    array.BinarySearch(.25, item => item.Value); 
} 
0

最好的方法是推出自己的。

public static class ListExtensions 
{ 
     public static T BinarySearchFirst<T>(this IList<T> list, Func<T, int> predicate) 
      where T : IComparable<T> 
    { 
     int min = 0; 
     int max = list.Count; 
     while (min < max) 
     { 
      int mid = (max + min)/2; 
      T midItem = list[mid]; 
      int comp = predicate(midItem); 
      if (comp < 0) 
      { 
       min = mid + 1; 
      } 
      else if (comp > 0) 
      { 
       max = mid - 1; 
      } 
      else 
      { 
       return midItem; 
      } 
     } 
     if (min == max && 
      predicate(list[min]) == 0) 
     { 
      return list[min]; 
     } 
     throw new InvalidOperationException("Item not found"); 
    } 
} 

用法:

var list = Enumerable.Range(1, 25).ToList(); 
var mid = list.Count/2; //13 

list.BinarySearchFirst(c => c >= 23 ? 0 : -1); // 23 

基于Can LINQ use binary search when the collection is ordered?

+1

假设他真的想线性搜索,从数组中的第一项开始。二进制搜索引起我相信他希望得到比O(n)更快的答案。 – 2013-02-26 19:55:53

+0

@RobertHarvey我忘了二进制搜索部分让我修改我的答案。 – Romoku 2013-02-26 19:56:41