二分查找
不同的二分查找
用递归实现的二分查找
static int BinarySearch < T> ( IList< T> list, T target)
where T : IComparable< T>
{
return BinarySearch ( list, 0 , list. Count - 1 , target) ;
}
static int BinarySearch < T> ( IList< T> list, int low, int high, T target)
where T : IComparable< T>
{
if ( low > high)
return - 1 ;
int mid = ( high - low) / 2 + low;
int comp = list[ mid] . CompareTo ( target) ;
if ( comp == 0 )
return mid;
if ( comp < 0 )
return BinarySearch ( list, mid + 1 , high, target) ;
else
return BinarySearch ( list, low, mid - 1 , target) ;
}
用迭代实现的二分查找
public static int BinarySearch < T> ( IList< T> list, T target)
where T : IComparable< T>
{
int low = 0 , high = list. Count - 1 ;
while ( low <= high) {
int mid = ( high - low) / 2 + low;
int comp = list[ mid] . CompareTo ( target) ;
if ( comp == 0 )
return mid;
if ( comp < 0 )
low = mid + 1 ;
else
high = mid - 1 ;
}
return - 1 ;
}
一些疑惑
为什么要使用comp
保存CompareTo
的结果? 对T
来说,CompareTo
的开销可能较大,用comp
保存结果可以减少一次比较
为什么要用(high - low) / 2 + low
而非(high + low) / 2
? (high + low) / 2
有溢出的风险,而经过计算我们可以发现(high - low) / 2 + low
恒等于(high + low) / 2
为什么使用[low, high]
(闭区间)作为范围? 这是便于理解的需要,选用[low, high]
或是[low, high)
取决于你会不会访问list[high]
一些问题
如果有多个target
存在于list
中,那么返回哪一个是不确定的 我们希望返回第一个或返回最后一个
如果target
不存在于list
中,只返回-1
毋宁说,如果target
寻找失败,就返回一个负数,那么我们为什么不让这个负数携带更多信息 呢 最常见的是返回的这个负数k
,有list[n less than ~k] < target < list[n greater than ~k]
(~k
代表按位取反 ,~k
总非负),即返回tar