二分搜索的总结

注意,以下用mid=lo+((hi-lo)>>1)是为了防止溢出。此处的小括号不是多余的,和运算符的优先级有关系。

题一、二分搜索,如果存在,返回其下标值,如果不存在,返回-1

版本1:lo表示最低位置,hi表示最高位置。

int binarySearch(int*A,int n,int value)

{

         int lo=0,hi=n-1;

         while(lo<=hi)

         {

                  int mid=lo+((hi-lo)>>1);

                  if(A[mid]>value)

                          hi=mid-1;

                  elseif(A[mid]<value)

                          lo=mid+1;

                  else

                          return mid;

         }

         return -1;

}

这段程序中,搜索的关键字总是在[lo,hi]即左右都是闭区间,因此,最后终止的搜索条件是lo<hi,即lo<=hi时就一直执行while循环。在lo<hi 时,[lo,hi]已经没有元素了,循环终止。

版本二:lo表示最低位置,hi表示最高位置+1,即hi的位置的数不能取。

int binarySearch(int*A,int n,int value)

{

         int lo=0,hi=n;

         while(lo<hi)

         {

                  int mid=lo+((hi-lo)>>1);

                  if(A[mid]>value)

                          hi=mid;

                  elseif(A[mid]<value)

                          lo=mid+1;

                  else

                          return mid;

         }

         return -1;

}

这段程序中,搜索的关键字总是在[lo,hi)即左闭右开区间,因此,最后终止的搜索条件是lo=hi,即lo<hi时就一直执行while循环。在lo=hi时,[lo,hi)已经没有元素了,循环终止。

题二、如果存在多个目标数,则返回其第一次出现的下标值

对应的题一的两个版本的代码如下所示:

int binarySearch(int*A,int n,intvalue)

{

         intlo=0,hi=n-1;

         intfirst=-1;

         while(lo<=hi)

         {

                  intmid=lo+((hi-lo)>>1);

                  if(A[mid]>value)

                          hi=mid-1;

                  else if(A[mid]<value)

                          lo=mid+1;

                  else

                  {

                          first=mid;

                          hi=mid-1;

                  }

         }

         return first;

}

 

int binarySearch(int *A,int n,int value)

{

         int lo=0,hi=n;

         int first=-1;

         while(lo<hi)

         {

                  int mid=lo+((hi-lo)>>1);

                  if(A[mid]>value)

                          hi=mid;

                  else if(A[mid]<value)

                          lo=mid+1;

                  else

                  {

                          first=mid;

                          hi=mid;

                  }

         }

         return first;

}

题三、如果要找的值有多个,则返回第一个所在的下标,如果不存在,则返回第一个比它大的值。

同样对应题一的两个版本的代码如下所示:

int binarySearch(int*A,int n,intvalue)

{

         intlo=0,hi=n-1;

         while(lo<=hi)

         {

                  in tmid=lo+((hi-lo)>>1);

                  if(A[mid]>=value)//hi+1中始终存储的是>=value的值

                          hi=mid-1;//所有>=value的值下标必然>=hi+1

                  else

                          lo=mid+1;

         }

         return hi+1;//return lo;结果一样

}

分析如下:当只剩下最后一个元素时,此时lo==hi,若这个元素last==value则hi=hi-1,此时hi指向的是前一个元素,因此需要将hi+1返回。若这个元素last!=value,那么lo=lo+1,而hi不变,此时hi所指向的必然是最后一个比value小的元素,因此返回hi+1。如果用return lo来代替,分析结果类似。

int binarySearch(int*A,int n,intvalue)

{

         intlo=0,hi=n;

         while(lo<hi)

         {

                  intmid=lo+((hi-lo)>>1);

                  if(A[mid]>=value)//hi中始终存储的是>=value的值

                          hi=mid;//所有>=value的值下标必然>=hi

                  else

                          lo=mid+1;

         }

         return hi;

}//必然会终止,不会出现[lo,lo+1)的死循环,把A[lo]>=value和A[lo]<value带入循环即可得出此结论

如屏蔽掉的解释所说,所有>=value的值的下标必然>=hi,因此直接返回hi即可。

注:题三的解法可以用于题二的解中,只需要判断最后的返回值是否是value即可,如果是,则返回,如果不是则返回-1即可和二等价,下面只给出第二个版本对应的代码,第一个类似。

int binarySearch(int*A,int n,intvalue)

{

         intlo=0,hi=n;

         while(lo<hi)

         {

                  intmid=lo+((hi-lo)>>1);

                  if(A[mid]>=value)

                          hi=mid;

                  else

                          lo=mid+1;

         }

         if(hi==n|| A[hi]!=value) //注意此处边界值的判断

                  return-1;

         return hi;

}

题四、如果要找的值有多个,则返回最后一个所在的下标,如果不存在,则返回第一个比它小的值。

对应题一的两个版本的代码如下所示:注意此处有所不同,题一的第二个版本中区间是[lo,hi),此处是 (lo,hi]。

int binarySearch(int*A,int n,int value)

{

         int lo=0,hi=n-1;

         while(lo<=hi)

         {

                  intmid=lo+((hi-lo)>>1);

                  if(A[mid]>value)

                          hi=mid-1;

                  else

                          lo=mid+1;

         }

         return lo-1;//return hi;结果一样

}

 

int binarySearch(int*A,int n,intvalue)

{

         intlo=-1,hi=n-1;

         while(lo+1<hi) //和上面的程序不一样,这里不能保证循环终止,可能会出现[lo,lo+1)的死循环,因此在此处判断用lo+1<hi,如果终止时lo+1==hi,则用下面的if语句判断A[hi]的值。

         {

                  intmid=lo+((hi-lo)>>1);

                  if(A[mid]>value)

                          hi=mid-1;

                  else

                          lo=mid;

         }

         if(lo+1==hi&& A[hi]<=target)

                  returnhi;

         returnlo;

}

由代码复杂度可以看出,还是用比较常规的[lo,hi]来解题比较方便。

分析和题3类似。

参考网站:http://www.cppblog.com/converse/archive/2009/10/05/97905.html

和http://blog.csdn.net/sunmenggmail/article/details/7540970

参考书:《编程珠玑》第四章,第五章

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值