[关闭]
@Lervard 2014-03-16T15:32:04.000000Z 字数 2854 阅读 1102

二分查找

简介

二分查找作为高效的查找算法,可以说是每个学计算机的都应该懂的,在每年的面试中,可以说是必须考察的点;

其实我们小时候就用过这个算法,只是没注意罢了,比如一本书300页,你要找第100页,你翻到了第20页,那么你肯定向后翻,你又翻到了第80页,你肯定继续向后找,每次砍掉一些。还比如英语字典,是按照单词的字典序排列的,你也是利用上面的算法在找。其实这就是二分查找。

适用范围

有序的线性表(一定得是数组存储的,由于需要快速取得对应位置的值)

需要注意的问题

int binarySearch(int arr[], int beg, int end, int target)

1、安全性检测

2、特殊判断
如何出入的是一个空数组,此时beg==end==0,计算mid会得0,然后访问arr[0]会报错所以应该加一句:

    if (beg == end && beg == 0)
        return -1;

3、注意mid的求法:

/*method1:*/ int mid = (beg + end) / 2;
/*method2:*/ int mid = beg + (end - beg) /2 ;
/*method3:*/ int mid = beg + ((end - beg) >> 1);

方法1:存在溢出的风险例如0x02 0x7fffffff
方法2、方法3:对于现代的编译器,两者执行效率应该一样;
注意:加法的优先级大于右移,所以需要在>>操作加括号(掉过坑,冏)
何的博文中有一个网友提到的(beg + end)/2的语意是向0取整而不是向下取整,比如(-3 + 2)/ 2 == 0的,而beg + (end - beg) / 2是向下取整则为-1
4、循环的结束条件
循环和递归程序应注意的三点:1、初始条件;2、转换条件;3、终止条件;
对于二分需要注意的是终止条件情况比较复杂,可以利用画图来描述
beg———-mid————end
beg <= mid <= end 是天然成立的
分类讨论:
arr[mid] < target 说明目标值在mid的右边
arr[mid] == target 恰好等于目标值
arr[mid] > target 目标值在mid的左边
最终结束条件(除随机选择一个与目标值相等的需求)是beg == end 或者beg + 1 == end刚好在临界点,判断条件一般是while (beg + 1 < end)可以避免死循环

分类(参考编程之美)

给定一个有序(不降序)数组arr,求解任意一个i使得arr[i]等于v,不存在则返回-1

  1. int findEqual(int arr[], int beg, int end, int target)
  2. {
  3. assert(0 <= beg && beg <= end);
  4. int mid = -1;
  5. int ret = -1;
  6. while (beg <= end)
  7. {
  8. mid = beg + ((end - beg)>>1);
  9. if (arr[mid] == target)
  10. {
  11. ret = mid;
  12. break;
  13. }else if (arr[mid] > target){
  14. end = mid - 1;
  15. }else {
  16. beg = mid + 1;
  17. }
  18. }
  19. return ret;
  20. }

给定一个有序(不降序)数组arr,求解最小的i使得arr[i]等于v,不存在则返回-1

  1. int findMinEqual(int arr[], int beg, int end, int target)
  2. {
  3. assert(0 <= beg && beg <= end);
  4. int mid = -1;
  5. int ret = -1;
  6. while (beg <= end)
  7. {
  8. mid = beg + ((end - beg)>>1);
  9. if (arr[mid] == target)
  10. {
  11. if (mid - 1 >= 0 && arr[mid - 1] == target)
  12. end = mid - 1;
  13. else{
  14. ret = mid;
  15. break;
  16. }
  17. }else if (arr[mid] > target){
  18. end = mid - 1;
  19. }else {
  20. beg = mid + 1;
  21. }
  22. }
  23. return ret;
  24. }

给定一个有序(不降序)数组arr,求解最大i使得arr[i]等于v,不存在则返回-1

  1. int findMaxEqual(int arr[], int beg, int end, int target)
  2. {
  3. assert(0 <= beg && beg <= end);
  4. int mid = -1;
  5. int ret = -1;
  6. while (beg <= end)
  7. {
  8. mid = beg + ((end - beg)>>1);
  9. if (arr[mid] == target)
  10. {
  11. if (mid + 1 <= end && arr[mid + 1] == target)
  12. {
  13. beg = mid + 1;
  14. }else{
  15. ret = mid;
  16. break;
  17. }
  18. }else if (arr[mid] > target){
  19. end = mid - 1;
  20. }else {
  21. beg = mid + 1;
  22. }
  23. }
  24. return ret;
  25. }

给定一个有序(不降序)数组arr,求解最大i使得arr[i]小于v,不存在则返回-1

  1. int findMaxLess(int arr[], int beg, int end, int target)
  2. {
  3. assert(0 <= beg && beg <= end);
  4. int mid = -1;
  5. while (beg + 1 < end)
  6. {
  7. mid = beg + ((end - beg)>>1);
  8. if (arr[mid] >= target)
  9. {
  10. end = mid - 1;
  11. }else{
  12. beg = mid;
  13. }
  14. }
  15. if (arr[end] < target)
  16. return end;
  17. else if (arr[beg] < target)
  18. return beg;
  19. else
  20. return -1;
  21. }

给定一个有序(不降序)数组arr,求解最小i使得arr[i]大于v,不存在则返回-1

  1. int findMinGreat(int arr[], int beg, int end, int target)
  2. {
  3. assert(0 <= beg && beg <= end);
  4. int mid = -1;
  5. while (beg + 1 < end)
  6. {
  7. mid = beg + ((end - beg)>>1);
  8. if (arr[mid] <= target)
  9. beg = mid + 1;
  10. else
  11. end = mid;
  12. }
  13. if (arr[beg] > target)
  14. return beg;
  15. else if (arr[end] > target)
  16. return end;
  17. else
  18. return -1;
  19. }
  20. /*别人的写法*/
  21. int findOther(int arr[], int beg, int end, int target)
  22. {
  23. int mid = -1;
  24. while (beg <= end)
  25. {
  26. mid = beg + (end - beg) / 2;
  27. if (arr[mid] <= target)
  28. beg = mid + 1;
  29. else
  30. end = mid - 1;
  31. }
  32. if (arr[beg] <= target)
  33. return -1;
  34. else
  35. return beg;
  36. }

一些不常见的写法

引用貌似得翻墙

声明

由于水平有限,若发现错误请告知,共同进步;

参考

1、二分查找(Binary Search)需要注意的问题,以及在数据库内核中的实现
2、编程之美p261页

下期预告

字符串专题,欢迎继续支持

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注