二分查找法

来源:互联网 发布:java类变量初始化 编辑:程序博客网 时间:2024/06/07 06:19

二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好,占用系统内存较少。

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


对于二分查找法,首先我们获取需要查找的数组的左边界l和右边界r,然后在通过左右边界计算出数组中中间的位置mid,但是计算mid不能简单的使用mid=(l+r)/2去计算,因为当l和r都接近于int的最大值时,我们求l+r就会发生int变量越界的情况,因此我们这样去求mid的值:mid=l+(l+r)/2(左边界加上一半的偏移量)。

具体如下图所示:



也可以运用递归的思想去实现二叉搜索,先判断我们要查找的target与mid处值的大小,如果运气非常好,target=arr[mid]的话,则直接return target就好了,如果小于mid,则把搜索的边界缩小,使其右边界为mid-1,相反,如果大于mid,则使其左边界变为mid+1,总之,就是在不断的缩小数组的查找范围,每一次查找都能排除上一步一半的数据,因此,二叉搜索是一种非常高效的搜索方法,以下是具体的代码:

#include <iostream>#include <cassert>#include <ctime>using namespace std;/**二分查找法,在有序数组中查找目标target * 返回目标target在数组中相对应的索引 * 如果数组中不存在目标target,则返回-1*/template <typename T>int binarysearch(T arr[],int n,T target)//n为数组的总数,target为要查询的目标{    //在[l,r]中搜索target    int l,r,mid;//l为搜索的左边界,r为搜索的右边界,mid为中间的元素    l=0,r=n-1;    while(l<=r){//注意此时l可以等于r        mid=l+(r-l)/2;//不采用(l+r)/2的算法求mid是为了防止Int变量越界        if(arr[mid]==target) return mid;        else if(target<arr[mid]){            r=mid-1;        }        else{            l=mid+1;        }    }    return -1;}template <typename T>int __binarysearch(T arr[],int l,int r,T target){//对数组中的[l,r]进行操作,l为起始搜索位置,r为终止搜索位置,mid为中间位置    if(l>r) return -1;    int mid;    mid=l+(r-l)/2;//不采用(l+r)/2的算法求mid是为了防止Int变量越界    if(target==arr[mid]) return mid;    else if(target<arr[mid]) __binarysearch(arr,l,mid-1,target);    else __binarysearch(arr,mid+1,r,target);}template <typename T>int binarysearch2(T arr[],int n,T target){   return  __binarysearch(arr,0,n-1,target);}//生成测试案例为一个大小为1000000的数组,查询超出1000000的则返回-1int main() {    //生成测试案例为一个大小为1000000的数组,查询超出1000000的则返回-1    int n=1000000;    int *a=new int[n];    for(int i=0;i<n;i++)    {        a[i]=i;    }//测试非递归算法clock_t starttime=clock();    for(int i=0;i<2*n;i++)    {        int ret=binarysearch(a,n,i);        if( i < n )            assert( ret== i );        else            assert( ret== -1 );    }    clock_t endtime=clock();    cout<<"Binary Search (Without Recursion):"<<double(endtime-starttime)/CLOCKS_PER_SEC<<'s'<<endl;    //测试递归的二叉搜索法    starttime=clock();    for(int i=0;i<2*n;i++)    {        int ret=binarysearch2(a,n,i);        if(i<n) assert(ret==i);        else assert(ret==-1);    }    endtime=clock();    cout<<"Binary Search (Recursion):"<<double(endtime-starttime)/CLOCKS_PER_SEC<<"s"<<endl;    delete[]a;    return 0;}

接下来我们看一下测试的结果:




我们发现,使用递归算法较好的描述了二分查找法,但是性能上却会略有下降。

原创粉丝点击