Exemplo n.º 1
0
 /// <summary>
 /// 使用指定的 <see cref="IComparer{T}"/> 泛型接口,在排序 <see cref="IList{T}"/> 的某个元素范围中搜索键值。
 /// </summary>
 /// <typeparam name="TElement">列表元素的类型。</typeparam>
 /// <typeparam name="TKey">要查找的键的类型。</typeparam>
 /// <param name="list">要搜索的从零开始的排序 <see cref="IList{T}"/>。</param>
 /// <param name="index">要搜索的范围的起始索引。</param>
 /// <param name="length">要搜索的范围的长度。</param>
 /// <param name="value">要搜索的键值。</param>
 /// <param name="keySelector">用于从元素中提取键的函数。</param>
 /// <param name="comparer">比较元素时要使用的 <see cref="IComparer{T}"/> 实现。</param>
 /// <returns>如果找到 <paramref name="value"/>,则为指定 <paramref name="list"/>
 /// 中的指定 <paramref name="value"/> 的索引。如果找不到 <paramref name="value"/>
 /// 且 <paramref name="value"/> 小于 <paramref name="list"/> 中的一个或多个元素,
 /// 则为一个负数,该负数是大于 <paramref name="value"/> 的第一个元素的索引的按位求补。
 /// 如果找不到 <paramref name="value"/> 且 <paramref name="value"/> 大于 <paramref name="list"/>
 /// 中的任何元素,则为一个负数,该负数是(最后一个元素的索引加 1)的按位求补。</returns>
 /// <exception cref="InvalidOperationException"><paramref name="comparer"/> 为 <c>null</c>,
 /// 且 <typeparamref name="TKey"/> 类型没有实现 <see cref="IComparable{T}"/> 泛型接口。</exception>
 private static int BinarySearchInternal <TElement, TKey>(this IList <TElement> list, int index, int length,
                                                          TKey value,
                                                          [NotNull] Func <TElement, TKey> keySelector,
                                                          [CanBeNull] IComparer <TKey> comparer)
 {
     Contract.Requires(list != null);
     Contract.Requires(keySelector != null);
     Contract.Requires(index >= 0 && index + length <= list.Count);
     Contract.Ensures((Contract.Result <int>() >= 0 && Contract.Result <int>() <= list.Count) ||
                      (Contract.Result <int>() < 0 && ~Contract.Result <int>() <= list.Count + 1));
     if (comparer == null)
     {
         comparer = Comparer <TKey> .Default;
     }
     try
     {
         var low  = index;
         var high = index + length - 1;
         while (low <= high)
         {
             var mid = low + ((high - low) >> 1);
             Contract.Assume(mid >= 0);
             var cmp = comparer.Compare(keySelector(list[mid]), value);
             if (cmp == 0)
             {
                 return(mid);
             }
             if (cmp < 0)
             {
                 low = mid + 1;
             }
             else
             {
                 high = mid - 1;
             }
         }
         return(~low);
     }
     catch (Exception ex)
     {
         throw CommonExceptions.CollectionItemCompareFailed(ex);
     }
 }
Exemplo n.º 2
0
 /// <summary>
 /// 使用指定的 <see cref="IComparer{T}"/> 泛型接口,在排序 <see cref="IList{T}"/> 的某个元素范围中搜索值。
 /// </summary>
 /// <typeparam name="T">列表元素的类型。</typeparam>
 /// <param name="list">要搜索的从零开始的排序 <see cref="IList{T}"/>。</param>
 /// <param name="index">要搜索的范围的起始索引。</param>
 /// <param name="length">要搜索的范围的长度。</param>
 /// <param name="value">要搜索的对象。</param>
 /// <param name="comparer">比较元素时要使用的 <see cref="IComparer{T}"/> 实现。</param>
 /// <returns>如果找到 <paramref name="value"/>,则为指定 <paramref name="list"/>
 /// 中的指定 <paramref name="value"/> 的索引。如果找不到 <paramref name="value"/>
 /// 且 <paramref name="value"/> 小于 <paramref name="list"/> 中的一个或多个元素,
 /// 则为一个负数,该负数是大于 <paramref name="value"/> 的第一个元素的索引的按位求补。
 /// 如果找不到 <paramref name="value"/> 且 <paramref name="value"/> 大于 <paramref name="list"/>
 /// 中的任何元素,则为一个负数,该负数是(最后一个元素的索引加 1)的按位求补。</returns>
 /// <exception cref="InvalidOperationException"><paramref name="comparer"/> 为 <c>null</c>,
 /// 且 <typeparamref name="T"/> 类型没有实现 <see cref="IComparable{T}"/> 泛型接口。</exception>
 private static int BinarySearchInternal <T>(this IList <T> list, int index, int length,
                                             T value, IComparer <T> comparer)
 {
     Contract.Requires(list != null);
     Contract.Requires(index >= 0 && index + length <= list.Count);
     Contract.Ensures((Contract.Result <int>() >= 0 && Contract.Result <int>() <= list.Count) ||
                      (Contract.Result <int>() < 0 && ~Contract.Result <int>() <= list.Count + 1));
     if (comparer == null)
     {
         comparer = Comparer <T> .Default;
     }
     try
     {
         int low  = index;
         int high = (index + length) - 1;
         while (low <= high)
         {
             int mid = low + ((high - low) >> 1);
             Contract.Assume(mid >= 0);
             int cmp = comparer.Compare(list[mid], value);
             if (cmp == 0)
             {
                 return(mid);
             }
             if (cmp < 0)
             {
                 low = mid + 1;
             }
             else
             {
                 high = mid - 1;
             }
         }
         return(~low);
     }
     catch (Exception ex)
     {
         throw CommonExceptions.CollectionItemCompareFailed(ex);
     }
 }