576-二分搜索算法(折半查找)

如果数据序列是无序的,我们采用的是线性搜索,时间复杂度是O(n)
在这里插入图片描述

二分搜索算法(折半查找)

是基于有序序列的搜索
在这里插入图片描述
我们定义2个下标,first和last
在这里插入图片描述
first初始值是0,last初始值是10
每次进行搜索,采用的策略是:
首先,计算出1个中间值:
在这里插入图片描述
(0+10)/2=5
在这里插入图片描述
然后把中间的值57和我们要搜索的元素val值比较

在这里插入图片描述
如果我们要搜索的元素的值是57,等于这个中间值,那么就找到了。

如果我们要搜索的元素的值大于这个中间值57
因为是数据有序的序列,所以我们要搜索的元素值大于这个中间值57的话,我们要搜索的元素肯定在57的右边。就不用在57的左边序列中去找。
在这里插入图片描述

如果我们要搜索的元素的值小于这个中间值57
因为是数据有序的序列,所以我们要搜索的元素值小于这个中间值57的话,我们要搜索的元素肯定在57的左边。就不用在57的右边序列中去找。
在这里插入图片描述
然后又来计算新的middle值
(0+4)/2=2
在这里插入图片描述
然后拿要搜索的元素的val值和这个中间值34对比

如果这个val值大于这个中间值34
在这里插入图片描述
然后计算新的middle值(3+4)/2=3
在这里插入图片描述
然后val值和这个中间值39比较,
如果这个val值小于这个中间值39,如果执行last=middle-1的话

在这里插入图片描述
这样是错误的,因为first是起始下标,last是末尾下标。说明这次找的是34-39之间的数字,所以在序列中不存在,找不到!

如果这个val值大于这个中间值39
first=middle+1
在这里插入图片描述
现在first和last相等了,如果找的是45,就找到了,如果比45小,或者比45大,就是表示在序列中找不到了,继续调整下标了,就是非法了,使first和last位置顺序乱套了,退出while循环,return -1了。

所以,我们规定:
在这里插入图片描述

二分搜索算法非递归实现

//二分搜索非递归实现
int BinarySearch(int arr[], int size, int val)
{

    int first = 0;
    int last = size - 1;

    while (first <= last)
    {
        int mid = (first + last) / 2;
        if (arr[mid] == val)
        {
            return mid;//找到了,返回下标 
        }
        else if (arr[mid] > val)//要找的元素的值比中间值小 
        {
            last = mid - 1;//到中间值的左边序列搜索 
        }
        else//要找的元素的值比中间值大 
        {
            first = mid + 1;//到中间值的右边序列搜索 
        }
    }

    return -1;//找不到,返回-1 
}

二分搜索算法的时间复杂度

为什么在有序的序列里,我们要使用二分搜索,而不使用线性搜索?
线性搜索的时间复杂度是O(n)
二分搜索的时间复杂度是O(logn)
对数时间比线性时间好的多
为什么二分搜索的时间是对数时间呢?
在这里插入图片描述
它是怎么搜索的?
因为刚开始first是0,last是10,(0+10)/2=5,所以它先搜的是57,它拿57作为入口,如果搜索的元素的值==57,就搜到了,就走人了
如果搜索的元素值小于57,就(0+4)/2=2,就和2号位置的34比较
如果搜索的元素的值小于34,就(0+1)/2=1,和1号位置的25比较
如果搜索的元素的值小于25,first和last都跑到0号位置了,就和0号位置的12比较,如果相等就找到了,如果不相等就是找不到。

如果搜索的元素的值大于34,first=3,(3+4)/2=3,和39比较,
如果比39小,就没了,first就跑到last的后面了,
如果比39大,first和last跑到45元素了,和45比较。
在这里插入图片描述

如果搜索的元素值大于57,first跑到6号位置,(6+10)/2=8,比较元素82,
如果搜索的元素比82小,last跑到7号位置,(6+7)/2=6,和63比较
如果比63小,就没有了,first跑到last的后面了,结束了。
如果比63大,first和last跑到7号位置,和78比较
如果比82大,first跑到9号位置,(9+10)/2=9,可以和96比较
比96小就没了,比96大,还可以和100比较

在这里插入图片描述
二分搜索相当于就是从这棵二叉树的根节点开始时,沿着某一个路径进行搜索的过程,最多搜到叶子节点上。
这是一棵BST树,二叉搜索树
左孩子的值小于父节点的值,父节点的值小于右孩子的值。
在这里插入图片描述
二分搜索在每一层只会搜索1个节点
在这里插入图片描述
所以,在这里插入图片描述
二叉树的层数和对应的节点数的关系:
在这里插入图片描述
n就是节点总个数

在这里插入图片描述
我们可以把1省略掉,因为这个1相当于根节点,根节点肯定是最先走的节点,我们就省略掉。
树的层数:L

在这里插入图片描述
在这里插入图片描述

二分搜索的高效率应用场景

如果我们有100w个数据,是有序的,最多搜log以2为底的100w
在这里插入图片描述
在这里插入图片描述
最多搜索20次就可以了!在这里插入图片描述
在有序的1000w个数据中搜索,最多搜索24次就可以了!
在这里插入图片描述

递归复习图解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
递的过程是在不断缩小问题的规模,缩小问题规模的过程中,不同数据规模之间,它们求解的结果是有关系的,
递不是无穷无尽的递,递一次就要开辟一次空间,栈的空间是比较小的,所以对于大数据处理,最好使用非递归方法处理 ,递的过程,一定会有递的规模,数据规模小到问题的结果是已知的
递到最后最小问题规模的结果是已知的,然后把每一层的结果一直向上归回去,最后n问题规模的解就解出来了

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
求n的阶乘:
在这里插入图片描述
在这里插入图片描述

二分搜索算法的递归实现

在这里插入图片描述
在这里插入图片描述
第一步:
在这里插入图片描述
第二步:
在这里插入图片描述
第三步:
在这里插入图片描述
如果找到了,就把mid一直返回去
如果找不到,就把-1一直返回去

#include <iostream>
using namespace std;

//二分搜索递归代码
int BinarySearch(int arr[], int i, int j, int val)
{
    if (i > j)//递归结束的条件 
        return -1;

    int mid = (i + j) / 2;
    if (arr[mid] == val)
    {
        return mid;
    }
    else if (arr[mid] > val)
    {
        return BinarySearch(arr, i, mid - 1, val);
    }
    else
    {
        return BinarySearch(arr, mid + 1, j, val);
    }
}


//二分搜索非递归实现
int BinarySearch(int arr[], int size, int val)
{
    return BinarySearch(arr, 0, size - 1, val);
}

int main()
{
    int arr[] = { 12, 25, 34, 39, 45, 57, 63, 78, 82, 96, 100 };
    int size = sizeof arr / sizeof arr[0];
    cout << BinarySearch(arr, size, 39) << endl;
    cout << BinarySearch(arr, size, 45) << endl;
    cout << BinarySearch(arr, size, 12) << endl;
    cout << BinarySearch(arr, size, 64) << endl;

    return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林林林ZEYU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值