二分查找--整理

Posted 神犇(shenben)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分查找--整理相关的知识,希望对你有一定的参考价值。

二分查找,无论是从名字还是理论都十分简单一个算法,其博大精深,简直恐怖。Jon Bentley:90%以上的程序员无法正确无误的写出二分查找代码。

  别人不知道,反正我早上是写了好久,这个查找算法,将查找的复杂度从 o( n ) 降到了 o( logn ) ,当之无愧的的好算法,更是许多高级算法的优化策略之一。

  

  二分查找之基本思路

  虽然二分查找是一个很吊的算法,但是跟很多算法一样,需要使用的基础条件——序列有序!

  先假设一个单调非增序列:1 2 3 4 5 6 ,求找到3的位置,地球人都会马上这么想——一个一个找咯,可是这样很慢!

  于是有人想要加快查找速度,他们发现如果从中间开始找,那么每次比较后就至少可以排除一半的数,这就是二分查找的基本思想——折半。

  1)设置三个指针变量(应该说是指针性质的变量,索引也是可以的)——low ,mid 和 high,并且满足 mid = ( low + high ) / 2;

  2)设置循环,进行target值与mid存储值的比较,根据比较结果更新low或者high;

  3)在 2)中,若出现找到target的情况,则返回mid指针;如果一直找不到,则返回空指针。

  下面是代码:

   

复制代码
//方法一
int binary_search(int n, int v) { int low=0,high=n-1,mid; while (low<=high) { mid=(low+high)/2; if (a[mid]==v) return mid; if (a[mid]<v) low=mid+1; if (a[mid]>v) high=mid-1; } return -1; }
复制代码

  看起来好像没什么问题,实际上在一些情况下 ,答案会很奇怪:1 2 2 4 5,我们如果找2,答案 -> 2 (这是索引啊!)  

  那么问题来了,为什么是返回第二个,而不是第一个呢?其实很简单,当序列出现重复元素时,我们找到了当然是其中“任意”一个啦!

  但是其实往往我们需要处理的序列总是拥有重复元素的,所以,我们需要优化!

  我们先来分析原来的二分查找 —— left < mid <right ,即我们将“=”的情况全部交给mid处理,于是mid会给你各种答案:

  所以,我们不妨按这种规则来二分 —— left <= mid < right !

  我们可以看看代码:

 

复制代码
//方法二:返回第一个位置
int lowerBound(const int a[],const int size,const int target) { int low=0,high=size-1,mid; while(low<high) { mid=(low+high)/2; if(a[mid]<target) low=mid+1; else high=mid; } if(a[low]==target) return low; else return -1; }
复制代码

 

  这里我们会发现两种查找方式一个最明显的不同:方法一是找到答案立即返回,方法二则是一直找到最底部(当成树看)然后再返回!感觉方法二要一

  直找到底部好像会很慢,但是事实证明:方法一才是最慢的,所以我们以后可以抛弃第一种写法啦!

  当然,方法二是返回第一个位置,那么就会有返回最后一个位置的算法啦!

  上代码:

 

复制代码
//方法三:返回最后一个位置
int upperBound(const int a[], const int size, const int target) { int low=0,high=size-1,mid; while(low<high) { mid=(low+high)/2+1; if(a[mid]>target) high=mid-1; else low=mid; } if(a[high]==target) return high; else return -1; }
复制代码

 

  以上就是我们的二分查找算法,参考资料:数据结构与程序设计——C++语言描述(这真是一本好书!)

 

以上是关于二分查找--整理的主要内容,如果未能解决你的问题,请参考以下文章

二分查找大全

《漫画算法2》源码整理-1 二分查找树 AVL树 红黑树

各种类型的二分查找模版,我都整理好了

带你整理面试过程中常考的九大排序算法

关于二分查找

关于二分查找