二分查找法

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

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


对于二分查找法,首先我们获取需要查找的数组的左边界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的则返回-1



int 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;
}


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




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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值