二分搜索算法

来源:互联网 发布:淘宝上的头层牛皮沙发 编辑:程序博客网 时间:2024/04/30 06:20

1.        算法思想:分治,从表中间开始查找目标元素。如果找到一致元素,则查找成功。如果中间元素比目标元素小,则仍用二分查找方法查找表的后半部分(表是递增排列的),反之中间元素比目标元素大,则查找表的前半部分。

2.        前提条件:

1)        查找表必须为有序状态(递增排列或递减排列),本文使用的表中数据是递增的。

2)        查找表为数组形式(内存连续)的数据结构;如果是链表(内存不连续)的数据结构二分查找无法使用,即便采用二分查找的思想也达不到时间复杂度O(logN),因为无法直接定位中间元素(O(1))。

3.        优缺点:

1)        优点是比较次数少,查找速度快,平均性能好;

2)        缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

4.        二分搜索的三种实现:

1)        版本一:查找范围为[lowbound, highbound):左闭右开

int binarysearch(int targetarray[],intlowbound,int highbound,int targetvalue){   int mid;    while(lowbound<highbound)//注意此处是严格的<号    {       mid=lowbound+(highbound-lowbound)/2;//这样可以避免数据的溢出       if(targetarray[mid]==targetvalue)       {           return mid;       }        if(targetarray[mid]>targetvalue)       {           highbound=mid;//注意此处没有-1       }       else       {           lowbound=mid+1;       }    }   return -1;//找不到返回-1}

2)        版本二: 查找范围为[lowbound, highbound]

int binarysearch(int targetarray[],intlowbound,int highbound,int targetvalue){   int mid;    while(lowbound<=highbound)//注意此处是<=号    {       mid=lowbound+(highbound-lowbound)/2;//这样可以避免数据的溢出       if(targetarray[mid]==targetvalue)       {           return mid;       }        if(targetarray[mid]>targetvalue)       {           highbound=mid-1;//注意此处有-1       }       else       {           lowbound=mid+1;       }    }   return -1;//找不到返回-1}

3)        递归版本的版本2:

int recursivebinarysearch(int a[10],intlow,int high,int target){   if(low>high)    {       return -1;}    int mid=low+(high-low)/2;   if(a[mid]==target)    {       return mid;}    if(a[mid]<target)    {       return recursivebinarysearch(a,mid+1,high,target);//分治    }   return recursivebinarysearch(a,low,mid-1,target);}

5.        时间复杂度为:O(logN)。空间复杂度为:O(1)
时间复杂度分析:以版本2为例。在while循环内部的所有语句用时O(1),所以主要分析循环次数。初始状态highbound-lowbound假设为N,每次这个差值至少减少一半,直至lowbound=highbound+1,所以大约最多执行logN次循环。所以时间复杂度为O(logN)。

6.        测试程序:

#include<iostream>usingnamespace std; inta[10]= {0,1,2,3,4,5,6,7,8,9}; intbinarysearch1(int a[10],int low,int high,int target);int binarysearch2(inta[10],int low,int high,int target);intrecursivebinarysearch(int a[10],int low,int high,int target); intmain(){    cout<<"使用第一种查找函数,查找数字8,上下限分别为3,8;查找结果为:";    int result=binarysearch1(a,3,8,8);    if(result!=-1)    {        cout<<"已找到,下标为:"<<result<<endl;    }    else    {        cout<<"没有找到"<<endl;    }     cout<<"使用第二种查找函数,查找数字8,上下限分别为3,8;查找结果为:";    int result2=binarysearch2(a,3,8,8);    if(result2!=-1)    {        cout<<"已找到,下标为:"<<result2<<endl;    }    else    {        cout<<"没有找到"<<endl;    }    cout<<"使用第三种查找函数,查找数字8,上下限分别为3,8;查找结果为:";     int result3=recursivebinarysearch(a,3,8,8);    if(result3!=-1)    {        cout<<"已找到,下标为:"<<result2<<endl;    }    else    {        cout<<"没有找到"<<endl;    }    return 0;} intbinarysearch1(int a[10],int low,int high,int target){    while(low<high)    {        int m=low+(high-low)/2;         if(a[m]==target)        {            return m;        }         if(a[m]>target)        {            high=m;        }        else        {            low=m+1;        }    }    return -1;} intbinarysearch2(int a[10],int low,int high,int target){    while(low<=high)    {        int m=low+(high-low)/2;        if(a[m]==target)        {            return m;        }         if(a[m]>target)        {            high=m-1;        }        else        {            low=m+1;        }    }    return -1;} intrecursivebinarysearch(int a[10],int low,int high,int target){    if(low>high)    {        return -1;    }     int mid=low+(high-low)/2;    if(a[mid]==target)    {        return mid;    }     if(a[mid]<target)    {        returnrecursivebinarysearch(a,mid+1,high,target);    }    returnrecursivebinarysearch(a,low,mid-1,target);}

运行结果为:

使用第一种查找函数,查找数字8,上下限分别为3,8;查找结果为:没有找到

使用第二种查找函数,查找数字8,上下限分别为3,8;查找结果为:已找到,下标为:8

使用第三种查找函数,查找数字8,上下限分别为3,8;查找结果为:已找到,下标为:8

解析:版本一的二分查找查找的区间是:[lowbound,highbound),左闭右开:首先我们要知道对于一对整数求它们的平均值(int类型),平均值要么正好在中间,要么偏向小的一方,永远不可能偏向大的一方,该版本的while循环的退出条件是lowbound==highbound,因此highbound对应的数组元素永远不会被比较,因此如上例程序,第一种没有找到数字8;版本二的二分查找查找的区间是:[lowbound,highbound],左闭右闭,该版本的while循环的退出条件是lowbound==highbound+1,因此highbound对应的数组元素会被比较,因此如上例程序,第二种找到数字8。版本三的道理同版本二。

0 0
原创粉丝点击