【算法详解 | 二分查找】详解二分查找 \ 折半查找高效搜索算法 | 顺序数组最快搜索算法 | 递归循环解决二分查找问题

二分查找

by.Qin3Yu

本文需要读者掌握 顺序表 的操作基础,完整代码将在文章末尾展示。

顺序表相关操作可以参考我的往期博文:
【C++数据结构 | 顺序表速通】使用顺序表完成简单的成绩管理系统.by.Qin3Yu

文中所有代码使用 C++ 举例,且默认已使用部分头文件和 std 命名空间:

#include <iostream>
#include <vector>
using namespace std;

概念速览

二分查找概述

  • 二分查找 算法属于 搜索算法 的一种。它是一种高效的搜索算法,用于在有序数组或列表中查找特定元素的位置。
  • 二分查找的基本思想是通过将目标值与数组中间的元素进行比较,从而将搜索范围缩小一半。如果目标值小于中间元素,则继续在左侧子数组中进行二分查找;如果目标值大于中间元素,则继续在右侧子数组中进行二分查找;如果目标值等于中间元素,则直接返回该位置。通过重复这个过程,最终可以找到目标值或确定其不存在于数组中。
  • 二分查找算法的时间复杂度为 O(log n) ,且不需要额外存储空间。

二分查找通常被使用于符合以下条件的以下场景:

  1. 数组或列表是 有序 的;
  2. 静态 数据结构;
  3. 数据量较
  4. 只需要 快速确定 元素是否存在。

算法详解

逻辑解析

  • 二分查找,就是不断的对搜索范围进行折半,从而缩小搜索范围,我们用下面的数组来进行说明:

在这里插入图片描述

  • 在上面的有序数组中,我们要查找数组内是否存在值 31 ,于是我们可以如下图所示,使用三个指针,一个指向数组的最左端,一个指向数组的最右端,一个指向数组的中间。

在这里插入图片描述

  • 我们使用 leftrightmid 分别表示左、右、中指针,当前 mid 指向的值为 26 ,因为数组是有序数组,所以可以得知,我们要查找的值 31 一定在 26右侧 ,因此,我们将左指针 left 指针指向 mid 的后一位元素,然后重新计算出 mid 指针的位置:

在这里插入图片描述

  • 如图所示,当前 mid 指向的值为 44 ,比 31 小,因此我们要查找的 31 一定在 44 的左侧,因此,我们把右指针 right 指向 mid 的前一位元素,然后重新计算 mid 的位置:

在这里插入图片描述

  • 同理,mid 指向的值 30 小于 31 ,所以我们把 left 移到 mid 的后一位,然后重新计算 mid 的位置:

在这里插入图片描述

注意:在二分查找中,rightleft 重合属于正常现象,表示搜索范围只有一个数字。

  • 此时,我们再检查 mid 所指的值,就是我们要查找的 31,于是我们返回出对应的结果,表示成功查找到元素。
  • 我们在上一步的例子中做出一点修改,假如数组中没有我们要查找的值 31 ,则会产生一种情况,即 left 跑到 right 的右边,代表数组中没有我们要查找的元素:

在这里插入图片描述

代码实现

  • 在下例中,我们使用 vector 顺序表来保存数据,然后使用 binarySearch 方法表示二分搜索:
int main() {
    vector<int> data = {1,7,9,11,14,19,20,26,29,30,31,44,45,52,59};
    int target = 31;
    int result = binarySearch(data, target);
}
  • 首先,我们要声明左右指针,左指针指向数组最前端,即索引为 [0] ,右指针指向数组最右端,即索引为 [长度-1]
int left = 0;
int right = arr.size() - 1;
  • 在上文中我们提到,如果 left 指针移动到了 right 指针右边,则代表数组内没有对应的值,则返回 -1 ,表示没有目标值:
while (left <= right) {
    ...
}
return -1;
  • 接下来,我们要根据左右指针计算出中间指针 mid ,即左指针加上两指针之和除二:
int mid = left + (right - left) / 2;
  • 最后,我们来判断 mid 指针所指值与查找值的关系,如果相等,则返回成功目标值的索引:
if (arr[mid] == target) {
    return mid;  // 找到目标,返回索引
}
  • 如果 mid 所指值比目标值小,则证明目标值只可能在 mid 右边,我们将 left 指针移到 mid 指针后一位,从右侧子数字开始查找:

在这里插入图片描述

else if (arr[mid] < target) {
    left = mid + 1;  // 继续在右侧子数组中查找
}
  • 相反,如果 mid 所指值比目标值大,则证明目标值只可能在 mid 左边,我们将 right 指针移到 mid 指针前一位,从左侧子数字开始查找:

在这里插入图片描述

else {
    right = mid - 1;  // 继续在左侧子数组中查找
}
  • 将上述代码做出结合后,便是完整的二分查找代码,具体如下文所示。

完整算法代码

#include <iostream>
#include <vector>
using namespace std;

int binarySearch(const vector<int>& arr, int target) {
    int left = 0;
    int right = arr.size() - 1;

    while (left <= right) {
        int mid = left + (right - left) / 2;  // 防止(left + right)出现溢出

        if (arr[mid] == target) {
            return mid;  // 找到目标,返回索引
        } else if (arr[mid] < target) {
            left = mid + 1;  // 继续在右侧子数组中查找
        } else {
            right = mid - 1;  // 继续在左侧子数组中查找
        }
    }

    return -1;  // 没有找到目标,返回-1
}

int main() {
    vector<int> data = {1,7,9,11,14,19,20,26,29,30,31,44,45,52,59};
    int target = 31;
    int result = binarySearch(data, target);

    if (result != -1) {55
        cout << "成功查找到对应值!" << result << endl;
    } else {
        cout << "找不到对应值。" << endl;
    }

    return 0;
}

至此,二分查找的所有内容讲解完毕(=
感谢您的阅读(=
CSDN.by.Qin3Yu

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/364176.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows存储空间不足局域网文件共享 Dism备份系统空间不足

问题情景 在日常使用中难免遇到Windows的空间不足的情况&#xff0c;常用办法是清理垃圾释放空间&#xff0c;部分场景例如我们需要使用Dism备份完整系统&#xff0c;所以需要非常大的存储空间不够&#xff0c;如果空间不够什么才是最有效的方案呢&#xff1f; 我们假设身边没有…

【HarmonyOS 4.0 应用开发实战】TypeScript入门之模块化详讲

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

如何在Raspberry Pi上启用SSH并结合cpolar内网穿透实现公网远程访问本地树莓派

文章目录 如何通过 SSH 连接到树莓派步骤1. 在 Raspberry Pi 上启用 SSH步骤2. 查找树莓派的 IP 地址步骤3. SSH 到你的树莓派步骤 4. 在任何地点访问家中的树莓派4.1 安装 Cpolar4.2 cpolar进行token认证4.3 配置cpolar服务开机自启动4.4 查看映射到公网的隧道地址4.5 ssh公网…

Oracle函数使用

ROW_NUMBER函数 ROW_NUMBER() OVER(PARTITION BY column1 ORDER BY column2 DESC) -- 根据column1分组按column2降序排序生成序号&#xff0c;序号由小到大,会生成一个唯一的序号 -- 例如column2中有两列值都为1,那他们的序号会有一个在上一个在下ROW_NUMBER() OVER(ORDER BY …

Redis-持久机制

文章目录 为什么有持久化什么是持久化RDB文件创建SAVEBGSAVE 文件载入 优缺点 AOF日志步骤 对比数据恢复 总结 Redis是一个开源的内存数据结构存储系统&#xff0c;被广泛应用于Web应用中&#xff0c;可以用作数据库和缓存服务器。它具有高性能、高并发、高可用性等特点&#x…

计网——应用层

应用层 应用层协议原理 网络应用的体系结构 客户-服务器&#xff08;C/S&#xff09;体系结构 对等体&#xff08;P2P&#xff09;体系结构 C/S和P2P体系结构的混合体 客户-服务器&#xff08;C/S&#xff09;体系结构 服务器 服务器是一台一直运行的主机&#xff0c;需…

零基础小白到底要不要学习鸿蒙,看完这篇再决定吧~

随着华为鸿蒙系统的问世&#xff0c;不少技术小白在是否学习鸿蒙的问题上犹豫不决。鸿蒙作为华为自主研发的操作系统&#xff0c;拥有许多独特的技术优势和市场前景。但对于小白来说&#xff0c;是否值得投入时间和精力去学习鸿蒙开发呢&#xff1f; 1.鸿蒙系统开发&#xff1…

短视频去水印教程,免费一键获取视频、图片、文案【迅风去水印】

自媒体行业的蓬勃发展&#xff0c;让越来越多的创作者涌入其中。然而&#xff0c;剪辑过程中常常遭遇到一个令人头疼的问题&#xff0c;那就是视频或图片上的水印。这些水印不仅会影响到作品的美感&#xff0c;还可能侵犯到版权。为了帮大家解决这一难题&#xff0c;分享一个免…

新手不会Git也能玩Github吗?

新手不会Git也能玩Github吗&#xff1f; 前言使用Github的准备步骤使用一种访问外网资源的方法&#xff08;这一步才是新手最容易&#xff09;注册账号 创建一个自己的仓库创建完仓库后的界面 搜索你想要的代码类型以搜索坦克大战为例以下载烟花代码为例 总结 前言 说到Github&…

认识 SYN Flood 攻击

文章目录 1.什么是 SYN Flood 攻击&#xff1f;2.半连接与全连接队列3.如何防范 SYN Flood 攻击&#xff1f;参考文献 1.什么是 SYN Flood 攻击&#xff1f; SYN Flood 是互联网上最原始、最经典的 DDoS&#xff08;Distributed Denial of Service&#xff09;攻击之一。 SYN…

使用STM32的FMC/FSMC接口实现多路数据传输和并发操作的设计与应用

在基于STM32的系统中&#xff0c;FMC&#xff08;Flexible Memory Controller&#xff09;/FSMC&#xff08;Flexible Static Memory Controller&#xff09;接口可以用于实现多路数据传输和并发操作。通过合理的设计和应用&#xff0c;我们可以提高系统的数据处理速度和效率。…

XML详解

XML 简介 概述&#xff1a;Extensible Markup Language 可扩展标记语言 可扩展&#xff1a;标签都是自定义的。 功能 数据存储&#xff1a;XML 可以用来存储结构化数据&#xff0c;包括文本、数字、日期等各种类型的数据数据交换&#xff1a;XML 可以作为一种通用的数据交换格…

Elasticsearch(ES) 下载添加IK分词器

上文 通过Web请求对 Elasticsearch(ES) 进行索引的 增删查 操作 我们通过web请求 创建了一个索引 但 目前 我们的索引是不具有分词效果的 我们并没有为索引指定分词器 所以 我们目前加进去的数据 就会保持原样 没有分词的能力 我们执行get查询操作 会发现一个 mappings字段 它…

如何访问 Oracle OKE 集群

OKE是Oracle Cloud提供的托管Kubernetes服务&#xff0c;为用户提供强大而灵活的容器编排平台。在本文中&#xff0c;我们将详细介绍如何有效地与OKE集群进行交互&#xff0c;包括访问集群的不同方式、管理访问权限以及执行常见操作的步骤。 1 安装oci命令 1.1 在Oracle Linux…

算法总结归纳(第十天)(动态规划第三部分)(线性dp)

目录 一、简单线性dp 1、最长递增子序列 ①、题目描述 ②、解题思路 ③、代码实现 2、最长连续递增序列 ①、题目描述 ②、解题思路 ③、代码实现 3、最长重复子数组 ①、题目描述 ②、解题思路 ③、代码实现 4、最长公共子序列 ①、题目描述 ②、解题思路 ③、…

Spring Boot 整合 Redis 使用教程

作为开发者&#xff0c;相信大家都知道 Redis 的重要性。Redis 是使用 C 语言开发的一个高性能键值对数据库&#xff0c;是互联网技术领域使用最为广泛的存储中间件&#xff0c;它是「Remote Dictionary Service」的首字母缩写&#xff0c;也就是「远程字典服务」。 Redis 以超…

openharmony开发版应用安装签名

配置签名信息 应用/服务在真机设备上运行&#xff0c;需要提前为应用/服务进行签名&#xff0c;DevEco Studio为开发者提供了自动化签名方案&#xff0c;可以一键完成应用/服务签名。具体操作如下&#xff1a; 单击File > Project Structure > Project > Signing Con…

Pandas进阶--map映射,分组聚合和透视pivot_table详解

文章目录 1.Pandas的map映射&#xff08;1&#xff09;映射&#xff08;2&#xff09;map充当运算工具 2.数据分组和透视&#xff08;1&#xff09;分组统计 - groupby功能 是pandas最重要的功能&#xff08;2&#xff09;聚合agg 3.透视表pivot_table&#xff08;1&#xff09…

【大厂AI课学习笔记】1.3 人工智能产业发展(4)——泛在的人工智能

人工智能走向泛在。 泛在&#xff0c;就是广泛存在。&#xff08;下图来自腾讯AI课。&#xff09; 没办法&#xff0c;被百度抛弃了&#xff0c;想学习&#xff0c;课程打不开&#xff0c;只好投想腾讯的怀抱。 之前考过腾讯云的认证&#xff0c;课程做的还是条理很清晰。 主…

铁轨语义分割(Unet结合resnet系列)

数据介绍 一类是图片&#xff0c;一类是图像标签。 引入库&#xff0c;处理数据 import torch.nn as nn import torch import torch.nn.functional as F import os from PIL import Image import torch from torch.utils.data import Dataset import torchvision.transfor…