​​​【收录 Hello 算法】10.1 二分查找

目录

10.1   二分查找

10.1.1   区间表示方法

10.1.2   优点与局限性


10.1   二分查找

二分查找(binary search)是一种基于分治策略的高效搜索算法。它利用数据的有序性,每轮缩小一半搜索范围,直至找到目标元素或搜索区间为空为止。

Question

给定一个长度为 𝑛 的数组 nums ,元素按从小到大的顺序排列且不重复。请查找并返回元素 target 在该数组中的索引。若数组不包含该元素,则返回 −1 。示例如图 10-1 所示。

二分查找示例数据

图 10-1   二分查找示例数据

如图 10-2 所示,我们先初始化指针 𝑖=0 和 𝑗=𝑛−1 ,分别指向数组首元素和尾元素,代表搜索区间 [0,𝑛−1] 。请注意,中括号表示闭区间,其包含边界值本身。

接下来,循环执行以下两步。

  1. 计算中点索引 𝑚=⌊(𝑖+𝑗)/2⌋ ,其中 ⌊⌋ 表示向下取整操作。
  2. 判断 nums[m] 和 target 的大小关系,分为以下三种情况。
    1. 当 nums[m] < target 时,说明 target 在区间 [𝑚+1,𝑗] 中,因此执行 𝑖=𝑚+1 。
    2. 当 nums[m] > target 时,说明 target 在区间 [𝑖,𝑚−1] 中,因此执行 𝑗=𝑚−1 。
    3. 当 nums[m] = target 时,说明找到 target ,因此返回索引 𝑚 。

若数组不包含目标元素,搜索区间最终会缩小为空。此时返回 −1 。

<1><2><3><4><5><6><7>

binary_search_step4

图 10-2   二分查找流程

值得注意的是,由于 𝑖 和 𝑗 都是 int 类型,因此 𝑖+𝑗 可能会超出 int 类型的取值范围。为了避免大数越界,我们通常采用公式 𝑚=⌊𝑖+(𝑗−𝑖)/2⌋ 来计算中点。

代码如下所示:

binary_search.c

/* 二分查找(双闭区间) */
int binarySearch(int *nums, int len, int target) {// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素int i = 0, j = len - 1;// 循环,当搜索区间为空时跳出(当 i > j 时为空)while (i <= j) {int m = i + (j - i) / 2; // 计算中点索引 mif (nums[m] < target)    // 此情况说明 target 在区间 [m+1, j] 中i = m + 1;else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中j = m - 1;else // 找到目标元素,返回其索引return m;}// 未找到目标元素,返回 -1return -1;
}

时间复杂度为 𝑂(log⁡𝑛) :在二分循环中,区间每轮缩小一半,因此循环次数为 log2⁡𝑛 。

空间复杂度为 𝑂(1) :指针 𝑖 和 𝑗 使用常数大小空间。

10.1.1   区间表示方法

除了上述双闭区间外,常见的区间表示还有“左闭右开”区间,定义为 [0,𝑛) ,即左边界包含自身,右边界不包含自身。在该表示下,区间 [𝑖,𝑗) 在 𝑖=𝑗 时为空。

我们可以基于该表示实现具有相同功能的二分查找算法:

binary_search.c

/* 二分查找(左闭右开区间) */
int binarySearchLCRO(int *nums, int len, int target) {// 初始化左闭右开区间 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1int i = 0, j = len;// 循环,当搜索区间为空时跳出(当 i = j 时为空)while (i < j) {int m = i + (j - i) / 2; // 计算中点索引 mif (nums[m] < target)    // 此情况说明 target 在区间 [m+1, j) 中i = m + 1;else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中j = m;else // 找到目标元素,返回其索引return m;}// 未找到目标元素,返回 -1return -1;
}

如图 10-3 所示,在两种区间表示下,二分查找算法的初始化、循环条件和缩小区间操作皆有所不同。

由于“双闭区间”表示中的左右边界都被定义为闭区间,因此通过指针 𝑖 和指针 𝑗 缩小区间的操作也是对称的。这样更不容易出错,因此一般建议采用“双闭区间”的写法

两种区间定义

图 10-3   两种区间定义

10.1.2   优点与局限性

二分查找在时间和空间方面都有较好的性能。

  • 二分查找的时间效率高。在大数据量下,对数阶的时间复杂度具有显著优势。例如,当数据大小 𝑛=220 时,线性查找需要 220=1048576 轮循环,而二分查找仅需 log2⁡220=20 轮循环。
  • 二分查找无须额外空间。相较于需要借助额外空间的搜索算法(例如哈希查找),二分查找更加节省空间。

然而,二分查找并非适用于所有情况,主要有以下原因。

  • 二分查找仅适用于有序数据。若输入数据无序,为了使用二分查找而专门进行排序,得不偿失。因为排序算法的时间复杂度通常为 𝑂(𝑛log⁡𝑛) ,比线性查找和二分查找都更高。对于频繁插入元素的场景,为保持数组有序性,需要将元素插入到特定位置,时间复杂度为 𝑂(𝑛) ,也是非常昂贵的。
  • 二分查找仅适用于数组。二分查找需要跳跃式(非连续地)访问元素,而在链表中执行跳跃式访问的效率较低,因此不适合应用在链表或基于链表实现的数据结构。
  • 小数据量下,线性查找性能更佳。在线性查找中,每轮只需 1 次判断操作;而在二分查找中,需要 1 次加法、1 次除法、1 ~ 3 次判断操作、1 次加法(减法),共 4 ~ 6 个单元操作;因此,当数据量 𝑛 较小时,线性查找反而比二分查找更快。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中的类型转换

文章目录 C中的四种类型转换static_castreinterpret_castconst_castdynamic_cast RTTI C中的四种类型转换 C语言中已经存在类型转换了&#xff0c;为什么C还要提出自己风格的类型转换&#xff1f; C风格的转换格式很简单&#xff0c;但是有不少缺点的&#xff1a; 转换的可视…

​​​【收录 Hello 算法】第 10 章 搜索

目录 第 10 章 搜索 本章内容 第 10 章 搜索 搜索是一场未知的冒险&#xff0c;我们或许需要走遍神秘空间的每个角落&#xff0c;又或许可以快速锁定目标。 在这场寻觅之旅中&#xff0c;每一次探索都可能得到一个未曾料想的答案。 本章内容 10.1 二分查找10.2 二…

【如何检查 ONNX 模型是否正确?】onnx.checker.check_model 用法详解

以下是对 onnx.checker.check_model 函数文档的翻译&#xff1a; onnx.checker.check_model 检查模型的一致性&#xff0c;即模型在结构、格式和配置方面的正确性和完整性。 如果模型的 ir_version 设置不正确或高于检查器的 ir_version&#xff0c;或者模型在 metadata_pro…

Java序列化解密:技巧、陷阱与最佳实践

1. 概述Java序列化的概念与应用场景 1.1 序列化简介 在Java中&#xff0c;序列化机制允许我们将一个对象状态转换为一串字节序列&#xff0c;并可在稍后再将这串字节序列恢复为对象。这一特性极大地方便了对象的持久化处理与网络传输。 1.2 为何需要序列化 序列化主要用于两…

恶劣天候激光雷达点云模拟方法论文整理

恶劣天候点云模拟方法论文整理 模拟雨天点云&#xff1a;【AAAI2024】模拟雪天点云&#xff1a;【CVPR 2022 oral】模拟雾天点云&#xff1a;【ICCV2021】模拟点云恶劣天候的散射现象&#xff1a;【Arxiv 2021】模拟积水地面的水花飞溅点云&#xff1a;【RAL2022】 模拟雨天点云…

C#面:如何在.Net(C# )中如何取消一个窗体的关闭

可以通过重写窗体的Closing事件来取消窗体的关闭 private void Form1_Closing(object sender, CancelEventArgs e) {// 取消窗体的关闭e.Cancel true; } 在窗体的构造函数中&#xff0c;可以将Closing事件与上述方法进行关联&#xff1a; public Form1() {InitializeCompon…

蓝桥杯Web开发【模拟题三】15届

1.创意广告牌 在"绮幻山谷"的历史和"梦幻海湾"的繁华交汇之处&#xff0c;一块创意广告牌傲然矗立。它以木质纹理的背景勾勒出古朴氛围&#xff0c;上方倾斜的牌子写着"绮幻山谷的风吹到了梦幻海湾"&#xff0c;瞬间串联了过去与现在&#xff0…

EPIC免费领取《骑士精神2》 IGN9分神作骑士精神2限时免费领

EPIC免费领取《骑士精神2》 IGN9分神作骑士精神2限时免费领 最近Epic一直为玩家们送出各种游戏&#xff0c;从《龙腾世纪审判》到《模拟农场22》&#xff0c;而就在今天&#xff0c;epic又为玩家们送出了IGN评分9分高分的骑士精神2.这款游戏&#xff0c;该游戏是一款由Tripwir…

软考之信息系统管理:数据结构和算法

数据结构和算法 数据结构&#xff1a;数据的特性和数据之间存在的关系&#xff1b; 数据结构常用名词和术语&#xff1a; 数据是人们利用文字&#xff0c;数字等符号对现实世界的事物及其活动所做的描述数据元素简称元素&#xff0c;是数据的基本单位&#xff0c;通常作为一个整…

考研408操作系统篇-操作系统的基本概念1

操作系统的基本概念 操作系统的目标与应用环境有关。 在查询系统中人机交互性&#xff1b;应用于工业控制、武器控制以及多媒体环境下的OS&#xff0c;要求其具有实时性&#xff1b; 对于微机上的配置的OS&#xff0c;则更看重的是其使用的方便性 操作系统的目标 方便性&…

阿赵UE引擎C++编程学习笔记——常用容器TArray、TMap和TSet

大家好&#xff0c;我是阿赵   这次来熟悉一下UE引擎在写C时的一些特定的容器。 主要有三种&#xff0c;分别是TArray、TMap和TSet 一、 TArray TArray是标准的数组&#xff0c;通过下标来访问内容。数组里面的元素是可以重复的。   以下是TArray的一些用法举例&#xff1…

vue连接mqtt实现收发消息组件超级详细

基本概念&#xff1a; MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种基于发布/订阅模式的轻量级消息传输协议&#xff0c;专为低带宽、高延迟或不稳定的网络环境设计。以下是MQTT实现收发消息的基本原理&#xff1a; 客户端-服务器模型&#xff1a…

快速排序详解——多种实现方式

快速排序 快速排序是一种交换排序&#xff0c;是基于二叉树结构的交换排序方法&#xff0c;基本思想如下&#xff1a; 任取待排序元素序列中的某元素作为基准值&#xff0c;按照该排序码将待排序集合分割成两子序列&#xff0c;左子序列中所有元素均小于基准值&#xff0c;右子…

亚信安慧AntDB:可靠的数据处理和存储工具

AntDB数据库具有高性能、高可用性和高扩展性等诸多优点&#xff0c;能够高效应对庞大数据存储和处理需求&#xff0c;同时保障数据的安全和稳定。不论是企业级业务系统还是政府信息管理平台&#xff0c;AntDB都能够轻松胜任&#xff0c;展现出其强大的适应能力和可靠性。 其强…

数据量较小的表是否有必要添加索引问题分析

目录 前言一、分析前准备1.1、准备测试表和数据1.2、插入测试数据1.3、测试环境说明 二、具体业务分析2.1、单次查询耗时分析2.2、无索引并发查询服务器CPU占用率分析2.3、添加索引并发查询服务器CPU占用率分析 三、总结 前言 在一次节日活动我们系统访问量到达了平时的两倍&am…

【小沐学GIS】GDAL库安装和使用(C++、Python)

文章目录 1、简介2、下载和编译&#xff08;C&#xff09;2.1 二进制构建2.1.1 Conda2.1.2 Vcpkg 2.2 源代码构建2.2.1 nmake.opt方式构建2.2.2 generate_vcxproj.bat方式构建 2.3 命令行测试2.3.1 获取S57海图数据 2.4 代码测试2.4.1 读取tiff信息 3、Python3.1 安装3.2 测试3…

零基础入门篇④ 初识Python(注释、编码规范、关键字...)

Python从入门到精通系列专栏面向零基础以及需要进阶的读者倾心打造,9.9元订阅即可享受付费专栏权益,一个专栏带你吃透Python,专栏分为零基础入门篇、模块篇、网络爬虫篇、Web开发篇、办公自动化篇、数据分析篇…学习不断,持续更新,火热订阅中🔥专栏订阅地址 👉Python从…

C语言:通讯录管理系统的实现

如何来实现通信录呢&#xff1f; 人的信息包括&#xff1a;名字年龄性别电话地址&#xff0c;等来表示 想要实现的功能&#xff1a; 1、默认存放100个人的信息 2、增加联系人信息 3、删除指定联系人信息 4、查找联系人信息 5、修改联系人信息 6、对联系人信息排序 7、显示联系人…

C语言 | Leetcode C语言题解之第110题平衡二叉树

题目&#xff1a; 题解&#xff1a; int height(struct TreeNode* root) {if (root NULL) {return 0;}int leftHeight height(root->left);int rightHeight height(root->right);if (leftHeight -1 || rightHeight -1 || fabs(leftHeight - rightHeight) > 1) {…

Fortran: select type

Fortran: select type 实现类似C的template函数功能 module M_reduceuse mpi_f08interface reducemodule procedure reduce_scalar,reduce_arrayend interface reducecontains!!https://docs.open-mpi.org/en/v5.0.x/man-openmpi/man3/MPI_Reduce.3.htmlsubroutine reduce_ar…