算法之旅——二分查找

来源:互联网 发布:网络新媒体专业 编辑:程序博客网 时间:2024/04/30 23:45

        在介绍二分查找之前,先给大家讲一个故事吧:一个女生背着满书包的书进入图书馆,叮叮叮,图书馆的报警器响了,女孩赶紧把书从书包倒出来,准备一本一本的验证,看是哪本书有问题,一旁扫地的阿姨看不下去了,过来把书分成了两挪,先检查第一挪,叮叮叮,报警器响了,说明这一挪有问题,又把这一挪分成两挪,先检查其中一挪,要是哪一挪响了,就把这一挪继续分成两挪,继续检查,不到三回合,大妈就把有问题的哪本书找出了了得意。大妈用鄙视的眼神看着那女生,仿佛在说连O(n)跟O(log n)都分不清楚。好了,故事讲完了,看来扫地的人都很厉害哦,不禁想起了天龙八部里的扫地僧~,咳咳,又扯远了了。

       这里介绍的二分查找法跟大妈找书的方法如出一辙,二分查找又称折半查找,优点是比较的次数少,查找速度快,平均性能好,时间复杂度为O(log n);其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。其主要思想如下:对一个有序的数组arrary[n],需要查找一个数key,看key是否在该数组中。

(1)设置两个变量left和right, 使left=0,right=n-1,先取数组的中间的那个数arrary[middle] ,(tips:middle=left+(right-right)>>1,如此算middle值,可以防止溢出),将key和arrary[middle]比较,若key小于arrary[middle],说明key处于数组左边部分,令right=middle-1;若key大于arrary[middle],说明key处于数组右边部分,令right=middle+1

(2)根据新的left或right,取新数组的中间值middle=left+(right-right)>>1,将key和新的middle值比较,若key小于arrary[middle],说明key在数组左边部分,令right=middle-1;若key大于arrary[middle],说明key在数组右边部分,令right=middle+1

(3)重复步骤(2),直至left等于right,在这个过程中没找到了key值,就返回其在数组中的下标,没找到key就返回-1

下面给出一个具体的实例,看二分查找是怎样工作的

设已知数组为arrary[]={18,29,36,38,71,89,110,129,160},查找的值value=129

数值

18    

29   

36   

38   

71   

89   

110  

129  

160  

下标

0

1

2

3

4

5

6

7

8

首先令left=0,right=8,则middle=(8-0)/2= 4; 将value=129与arrary[middle]=arrary[4]=71比较,显然value大于arrary[middle],那么就令left=middle+1=4+1=5,新的middle值为left+(right-right)>>1=5+(8-5)/2=6, 将value与新的arrary[middle]=arrary[6]=110比较,value又大于arrary[middle],继续令left=middle+1=6+1=7,新的middle值为left+(right-right)>>1=7+(8-7)/2=7,再将value与arrary[7]=129比较,哈哈,value==arrary[7],终于找到了,看来二分法查找数据还是蛮快的嘛,仅仅用了三趟就找到了。

        由上面的查找过程可以看出,二分法比常规的顺序查找快多了,节省了很多时间,尤其是在数据量很大的时候,二分法更能显出其优势。不过使用二分法查找有一个不好的地方就是待查找的数组必须是有序的,可是是升序,也可以是降序,这就导致查找之前多了一个工作量——对数组排序,关于数组排序的算法,可以参考我的上一篇博客《算法之旅——快速排序》

好了,下面给出一份二分查找的参考代码(以下代码均已编译通过,正常运行)

//description:二分查找算法//author:hust_luojun//data:2014-7-16#include <iostream>using namespace std;int main(){    int binary_search(int arrary[],int length,int key);    int arrary[] = {7,18,29,36,38,71,89,110,129,160,222,225,265,360,361,721};    int key = 160;    int pos = binary_search(arrary,16,key);    for(int i=0;i<16;i++)    {        cout<<arrary[i]<<"  ";    }    cout<<endl;    cout<<"the number "<<key<<" that searched is in position: "<<pos<<endl;    return 0;}int binary_search(int arrary[],int length,int key){   if(arrary == NULL || length <= 0)        //错误处理        {            cout<<"error! the arrary is incorrect"<<endl;            return -1;        }   else    {        int left = 0;        int right = length - 1;        while(left <= right)            {                 int middle;                 int pos;                middle = left + ((right - left)>>1); //建议不要写成middle=(left+right)/2,防止数组很大时,溢出                if(key < arrary[middle])        //查找的数值key小于数组中间值                    {                        right = middle - 1;                    }                else if(key > arrary[middle])   //查找的数值key大于数组中间值                        {                            left = middle +1;                        }                    else if(key == arrary[middle])  //查找的数值key等于数组中间值                        {                            return middle;          //返回key在数组中的位置,即数组下标                        }            }       return -1;       //若数值key不在此数组中,返回-1    }}
附上程序运行的结果:


/*****码字不易,转载请注明出处*****/

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 给民俗差评老板骂你怎么办 华为p10后置摄像头调黑了怎么办 美图m6手机相机拍照模糊该怎么办 美图t8用久了卡怎么办 美图m4手机开不开机怎么办 比亚迪m6冷凝器散热不好怎么办 深圳市小汽车摇号审核没通过怎么办 扫码开门售货机拿了不给钱怎么办 预付卡办完后对方不愿退款怎么办 海尔88u52显示內存不足怎么办 京东账号绑定的手机好不用了怎么办 京东账号换手机了手机号没变怎么办 京东发票的号和手机对不起来怎么办 京东账号忘记了只有身份证怎么办啊 京东账号手机号换了忘记账号怎么办 新换的卡被注册过京东号怎么办 以旧换新旧的没给商家报案怎么办 宜家家居家居指南地址写错怎么办 苏宁任性付没还遭到恐吓心意怎么办 大王卡激活后一直是E网怎么办 京东退货已取走后悔了怎么办 退差价把下单立返红包退还了怎么办 苏宁电器发票丢了换电器怎么办 苹果5s访问限制密码忘了怎么办 京东买的暴风电视出现问题了怎么办 控水一个月的三角梅还没开花怎么办 帮别人办手机分期不还怎么办 国美在线没有信用卡分期不了怎么办 手机店办理分期被老板套现了怎么办 美的空调保修卡丢了怎么办 格力空调保修卡丢了怎么办 荣耀9i手机总是滑手怎么办? 春兰空调没发票不给修怎么办 洗衣机顶盖的安全开关坏了怎么办 苹果手机的开关健坏了怎么办 淘宝买的东西快递弄破损了怎么办 京东购买邮来手机里面没有怎么办 孕期建卡病历本丢了怎么办 四维检查胎儿心脏有缺陷怎么办 七个月的宝宝俩个蛋蛋都疝气怎么办 电脑有些网站看视频不能全屏怎么办