【算法系列 | 8】深入解析查找算法之—二分查找

序言

心若有阳光,你便会看见这个世界有那么多美好值得期待和向往。

决定开一个算法专栏,希望能帮助大家很好的了解算法。主要深入解析每个算法,从概念到示例。

我们一起努力,成为更好的自己!

今天第8讲,讲一下查找算法的二分查找

1 基础介绍

查找算法是很常见的一类问题,主要是将一组数据按照某种规则进行排序。

以下是一些常见的查找算法及其应用场景:

  1. 布隆过滤器(Bloom Filter):适用于判断一个元素是否存在于一个大规模的数据集中,时间复杂度为O(1),但有一定的误判率。
  2. 二分查找(Binary Search):适用于有序数组中查找元素,时间复杂度为O(log n);
  3. 哈希表查找(Hash Table:适用于快速查找和插入元素,时间复杂度为O(1),但需要额外的存储空间;
  4. 线性查找(Linear Search):适用于无序数组中查找元素,时间复杂度为O(n);
  5. 插值查找(Interpolation Search):适用于有序数组中查找元素,时间复杂度为O(log log n),但是对于分布不均匀的数据集效果不佳;
  6. 斐波那契查找(Fibonacci Search):适用于有序数组中查找元素,时间复杂度为O(log n),但需要额外的存储空间;
  7. 树表查找(Tree Search):适用于快速查找和插入元素,时间复杂度为O(log n),但需要额外的存储空间;
  8. B树查找(B-Tree):适用于大规模数据存储和查找,时间复杂度为O(log n),但需要额外的存储空间;

一、二分查找介绍

1.1 原理介绍

二分查找算法(Binary Search)是一种用于在有序数据集合中查找目标元素的高效搜索算法。

它的实现原理基于分而治之(Divide and Conquer)的思想,通过将查找范围逐渐缩小一半来快速定位目标元素。

下面详细讲解二分查找算法的实现原理:

前提条件

  • 数据集合必须是有序的通常是升序排列的。
  • 数据集合应为静态,不应频繁插入或删除元素。

步骤

  1. 初始化指针:首先,确定查找范围,通常是整个数据集合。然后,初始化两个指针:

    • 左指针left)指向查找范围的起始位置,通常是0。
    • 右指针right)指向查找范围的结束位置,通常是数据集合的最后一个元素的索引。
  2. 查找中间元素:计算左右指针的中间位置,即 (left + right) / 2

  3. 比较中间元素:将目标元素与中间位置的元素进行比较。

    • 如果目标元素等于中间位置的元素,则找到了目标元素,查找结束。
    • 如果目标元素小于中间位置的元素,则更新右指针为中间位置的前一个位置,将查找范围缩小为左半部分。
    • 如果目标元素大于中间位置的元素,则更新左指针为中间位置的后一个位置,将查找范围缩小为右半部分。
  4. 重复步骤2和步骤3:不断重复计算中间位置和比较中间元素,直到以下任一条件满足:

    • 找到目标元素,即目标元素等于中间位置的元素。
    • 左指针大于右指针,表示查找范围为空,目标元素不存在。

示例: 假设有一个有序数组 arr,要查找目标元素 target

arr = [1, 3, 5, 7, 9, 11, 13, 15, 17] target = 9

初始时,left 指向0,right 指向8,中间元素为 arr[4],即9。

  1. 目标元素与中间元素相等,查找结束,找到了目标元素。

二分查找算法的关键在于每一次迭代都将查找范围缩小一半,这导致算法的时间复杂度为 O(log n),其中 n 是数据集合的大小。这使得二分查找非常高效,特别适用于大规模的有序数据集合。但需要注意的是,由于它要求数据集合必须是有序的,因此如果数据无序,需要先进行排序操作。

 

1.2 优缺点

优点:

  1. 高效性:二分查找的时间复杂度为 O(log n),其中 n 是数组的长度。由于每次迭代都将搜索范围减半,因此算法的时间复杂度相对较低。在大型有序数组中,二分查找比线性查找要快得多。
  2. 简单易实现:二分查找的实现相对简单,只需按照一定的步骤进行比较和调整指针即可。

缺点:

  1. 仅适用于有序数组:二分查找要求数组必须是有序的,否则无法保证正确的查找结果。如果数组未排序,需要先进行排序操作,这可能会增加额外的时间复杂度。
  2. 内存占用较大:二分查找通常需要占用较大的内存空间,因为它需要存储整个数组。在某些情况下,这可能会成为一个问题,特别是当处理大型数组时。
  3. 难以处理插入和删除操作:二分查找适用于静态数组,即不经常进行插入和删除操作的数组。如果需要频繁地插入或删除元素,由于需要保持数组有序性,可能需要进行额外的操作,导致效率降低。

所以,二分查找算法在查找有序数组中的元素时非常高效。它的主要优点是高效性和简单易实现。

然而,它的缺点是仅适用于有序数组、内存占用较大以及难以处理插入和删除操作。

因此,在选择使用二分查找时,需要根据具体的问题和数据结构的特点综合考虑其优缺点。

1.3 复杂度

这种算法的效率很高,时间复杂度为O(log n),适用于大规模数据集合。

1.4 使用场景

二分查找适用于以下场景:

  1. 有序数组:二分查找要求数组是有序的,因此当我们需要在一个已排序的数组中查找某个元素时,可以使用二分查找来提高查找效率。

  2. 查找静态数据:如果数据集合是静态的,即不会频繁地插入、删除或修改元素,而是在固定的数据集上进行查找操作,那么二分查找是一个很好的选择。

  3. 大型数据集合:二分查找的时间复杂度为 O(log n),其中 n 是数组的长度。相比线性查找的 O(n) 时间复杂度,二分查找在大型数据集合中的查找效率更高。

  4. 查找边界值:由于二分查找可以快速定位有序数组中的中间元素,因此它在查找边界值或者某个特定范围内的元素时非常有用。例如,在一个有序整数数组中查找某个元素第一次出现的位置或最后一次出现的位置。

  5. 数值区间判断:对于满足某种数值规律的数组,可以使用二分查找进行区间判断。例如,对于一个有序的数值范围数组,可以使用二分查找确定某个数值是否在某个区间内。

二、代码实现

2.1 Python实现

代码示例

def binary_search(arr, target):left = 0right = len(arr) - 1while left <= right:mid = (left + right) // 2if arr[mid] == target:return midelif arr[mid] < target:left = mid + 1else:right = mid - 1return -1  # 如果未找到目标元素,返回 -1# 示例使用
arr = [1, 3, 5, 7, 9, 11, 13]
target = 7result = binary_search(arr, target)if result != -1:print("目标元素在数组中的索引为:", result)
else:print("目标元素不在数组中")

代码讲解

在这个示例中,我们定义了一个名为 binary_search 的函数,它接受一个有序数组 arr 和目标元素 target 作为输入参数。算法使用两个指针 left 和 right 来表示搜索的区间。开始时,left 指向数组的起始位置,right 指向数组的末尾位置。

然后,算法进入一个循环,当 left 小于等于 right 时,持续执行以下步骤:计算中间元素的索引 mid,并将其与目标元素进行比较。如果 arr[mid] 等于 target,则找到了目标元素,返回 mid。如果 arr[mid] 小于 target,则说明目标元素可能在 mid 的右侧,将 left 更新为 mid + 1

  1. 如果 arr[mid] 大于 target,则说明目标元素可能在 mid 的左侧,将 right 更新为 mid - 1
  2. 如果循环结束时仍未找到目标元素,说明目标元素不存在于数组中,返回 -1。

运行结果

运行上述代码的结果将会是:

目标元素在数组中的索引为: 3

根据给定的有序数组 [1, 3, 5, 7, 9, 11, 13] 和目标元素 7,经过二分查找算法,找到了目标元素在数组中的索引位置为 3。

2.2 Java实现

代码示例

public class BinarySearch {public static int binarySearch(int[] arr, int target) {int left = 0;int right = arr.length - 1;while (left <= right) {int mid = left + (right - left) / 2;if (arr[mid] == target) {return mid;} else if (arr[mid] < target) {left = mid + 1;} else {right = mid - 1;}}return -1;  // 如果未找到目标元素,返回 -1}// 示例使用public static void main(String[] args) {int[] arr = {1, 3, 5, 7, 9, 11, 13};int target = 7;int result = binarySearch(arr, target);if (result != -1) {System.out.println("目标元素在数组中的索引为: " + result);} else {System.out.println("目标元素不在数组中");}}
}

代码讲解

在这个示例中,定义了一个名为 BinarySearch 的类,其中包含了一个静态方法 binarySearch。该方法接受一个有序数组 arr 和目标元素 target 作为输入参数,并返回目标元素在数组中的索引。

在 binarySearch 方法中,使用两个指针 left 和 right 来表示搜索的区间。开始时,left 指向数组的起始位置,right 指向数组的末尾位置。

然后,算法进入一个循环,当 left 小于等于 right 时,持续执行以下步骤:

  1. 计算中间元素的索引 mid,并将其与目标元素进行比较。
  2. 如果 arr[mid] 等于 target,则找到了目标元素,返回 mid
  3. 如果 arr[mid] 小于 target,则说明目标元素可能在 mid 的右侧,将 left 更新为 mid + 1
  4. 如果 arr[mid] 大于 target,则说明目标元素可能在 mid 的左侧,将 right 更新为 mid - 1
  5. 如果循环结束时仍未找到目标元素,说明目标元素不存在于数组中,返回 -1。

运行结果

运行上述 Java 代码的结果将会是:

目标元素在数组中的索引为: 3

根据给定的有序数组 [1, 3, 5, 7, 9, 11, 13] 和目标元素 7,经过二分查找算法,找到了目标元素在数组中的索引位置为 3。

三、图书推荐

清华社【秋日阅读企划】领券立享优惠

IT好书 5折叠加10元 无门槛优惠券:活动

活动时间:9月4日-9月17日,先到先得,快快抢

图书名称:

  • 《Python从入门到精通(第3版)(软件开发视频大讲堂)》

图书介绍

《Python从入门到精通(第3版)》从初学者角度出发,通过通俗易懂的语言、丰富多彩的实例,详细介绍了使用Python进行程序开发应该掌握的各方面技术。

全书共分27章,包括初识Python、Python语言基础、运算符与表达式、流程控制语句、列表和元组、字典和集合、字符串、Python中使用正则表达式、函数、面向对象程序设计、模块、文件及目录操作、操作数据库、使用进程和线程、网络编程、异常处理及程序调试、Pygame游戏编程、推箱子游戏、网络爬虫开发、火车票分析助手、数据可视化、京东电商销售数据分析与预测、Web编程、Flask框架、e起去旅行网站、Python自动化办公、AI图像识别工具等内容。

书中所有知识都结合具体实例进行介绍,涉及的程序代码都给出了详细的注释,读者可轻松领会Python程序开发的精髓,快速提升开发技能。 

 

参与方式 

图书数量:本次送出 3 本   !!!⭐️⭐️⭐️
活动时间:截止到 2023-09-16 12:00:00

抽奖方式:

  • 评论区随机抽取小伙伴!

留言内容,以下方式都可以:

  • 根据文章内容进行高质量评论

参与方式:关注博主、点赞、收藏,评论区留言 

中奖名单 

🍓🍓 获奖名单🍓🍓

 中奖名单:请关注博主动态

名单公布时间:2023-09-16 下午

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

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

相关文章

IO day7

1->x.mind 2-> A进程 B进程

[Google DeepMind] LARGE LANGUAGE MODELS AS OPTIMIZERS

Large Language Models as Optimizers 文章链接 总体架构Optimization by PROmpting (OPRO)&#xff1a;最开始输入meta-prompt&#xff0c;这个初始的meta-prompt基本上只是对优化任务进行了描述(也会有few-shot example)。输入后LLM便会生成一个solution&#xff0c;这个sol…

Vue3:proxy数据取值proxy[Target]取值

vue3底层是使用proxy进行代理的&#xff0c;而proxy中[[Target]]才是想要的值。 获取target值的方式一&#xff1a; <script setup>//先引入toRawimport { toRaw } from vue;//再使用console.log(toRaw(数据名))</script> 获取target值的方式二&#xff1a; <…

NIO基础

一、NIO基础 Java New IO是从Java1.4版本开始引入的一个新的IO api&#xff0c;可以替代以往的标准IO&#xff0c;NIO相比原来的IO有同样的作用和目的&#xff0c;但是使用的方式完全不一样&#xff0c;NIO是面向缓冲区的&#xff0c;基于通道的IO操作&#xff0c;这也让它比传…

Java学习之--类和对象

&#x1f495;粗缯大布裹生涯&#xff0c;腹有诗书气自华&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;Java学习之--类和对象 类和对象 类的实例化&#xff1a; 1.什么叫做类的实例化 利用类创建一个具体的对象就叫做类的实例化&#xff01; 当我们创建了…

Vulnhub系列靶机---HarryPotter-Fawkes-哈利波特系列靶机-3

文章目录 信息收集主机发现端口扫描dirsearch扫描gobuster扫描 漏洞利用缓冲区溢出edb-debugger工具msf-pattern工具 docker容器内提权tcpdump流量分析容器外- sudo漏洞提权 靶机文档&#xff1a;HarryPotter: Fawkes 下载地址&#xff1a;Download (Mirror) 难易程度&#xff…

工厂除静电除尘设备--离子风枪

静电无处不在&#xff0c;区别在于静电的多少而已。特别是工业生产过程中&#xff0c;大量的静电会有很多危害。 静电的危害有几点&#xff1a;1.引起电子设备的故障或误动作&#xff0c;造成电磁干扰。2.击穿集成电路和精密的电子元件&#xff0c;或使元件老化&#xff0c;拉…

关于一个left join的易错点

很多人在学习mysql的时候应该都出现过很多问题&#xff0c;特别是连接方面的问题应该最多&#xff0c;希望这篇文章帮助到正在找bug的你 Java报错数据返回数量出现错误 遇到这种问题一定要看日志 很明显通过left join查询除了两条数据并且为空 马上思考错误的原因&#xff0c;…

【Java基础篇 | 面向对象】--- 聊聊什么是多态(上篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、什么是多态二、多…

数据结构基础7:二叉树【链式结构】实现和递归思想。

二叉树的链式结构实现 一.二叉树链式结构的实现&#xff1a;1.前置说明&#xff1a;1.创建二叉树&#xff1a;2.二叉树的结构&#xff1a; 2.二叉树的遍历&#xff1a;1.二叉树的前中后序遍历&#xff1a;2.内容拓展&#xff1a; 二.二叉树链式(题目)题目一&#xff1a;计算节点…

小程序源码:多功能口袋工具箱微信小程序源码-带流量主|云开发(更新)

这里主要分享多功能口袋工具箱微信小程序源码&#xff0c;有带流量主&#xff0c;而且超多功能工具箱组合的微信小程序源码。无需服务器即可搭建&#xff0c;可以设置流量主赚取收益。 源码链接&#xff1a; 网盘源码 密码&#xff1a;hma8 工具箱的应用一览&#xff1a; 1…

【计算机网络】传输层协议——TCP(上)

文章目录 TCPTCP协议段格式报头和有效载荷如何分离&#xff1f;4位首部长度 TCP可靠性确认应答机制的提出序号和确认序号为什么序号和确认序号在不同的字段&#xff1f; 16位窗口大小 6个标志位标志位本质具体标志位PSHRSTURG 超时重传机制 文章目录 TCPTCP协议段格式报头和有效…

Qt Designer UI设计布局小结

目录 前言1 居中布局2 左右布局3 上下布局4 复杂页面布局总结 前言 本文总结了在开发Qt应用程序时使用 Designer 进行UI布局的一些心得体会。Qt Designer是Qt提供的一个可视化界面设计工具&#xff0c;旨在帮助开发人员快速创建和布局用户界面。它提供了丰富的布局管理器和控件…

我的个人网站——宏夏Coding上线啦

网站地址&#xff1a;宏夏Coding Github地址&#xff1a;&#x1f525;&#x1f525;宏夏coding网站&#xff0c;致力于为编程学习者、互联网求职者提供最需要的内容&#xff01;网站内容包括求职秘籍&#xff0c;葵花宝典&#xff08;学习笔记&#xff09;&#xff0c;资源推…

线性代数的学习和整理20,关于向量/矩阵和正交相关,相似矩阵等(草稿)

目录 1 什么是正交 1.1 正交相关名词 1.2 正交的定义 1.3 正交向量 1.4 正交基 1.5 正交矩阵的特点 1.6 正交矩阵的用处 1 什么是正交 1.1 正交相关名词 orthogonal set 正交向量组正交变换orthogonal matrix 正交矩阵orthogonal basis 正交基orthogonal decompositio…

访问局域网内共享文件时报错0x80070043,找不到网络名

我是菜鸡 此篇只为分享一个我遇到的很简单的但是排查了好久的小问题。 我的网络环境是在校园网内&#xff0c; 自己的办公电脑设置了固定IP&#xff1a;10.11.128.236&#xff0c;同事电脑IP为&#xff1a;10.11.128.255 本人需要访问同事在局域网内分享的文件&#xff0c;…

关于vscode的GitLens插件里的FILE HISTORY理解

最近在用vscode的GitLens插件开发项目遇到这个疑问&#xff0c;先看图&#xff1a; 每当我点击FILE HISTORY 一个commit时&#xff0c;正常来说显示器会自动将点击的提交版本和它上一个提交版本进行比较&#xff0c;如果单纯这么理解的话就错了&#xff0c;因为GitLens的File …

富斯I6刷10通道固件

使用USB转串口模块刷写10通道固件 一、下载固件 1. 十通道英文固件 下载地址: https://github.com/benb0jangles/FlySky-i6-Mod-/tree/master 选择 FlySky-i6-Mod–master \ 10ch Mod i6 Updater \ 10ch_MOD_i6_Programmer_V1 路径下的文件,亲测可用。 2. 原版六通道中…

Android性能优化之应用瘦身(APK瘦身)

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览2.1 apk组成 三、优化方向3.1 源代码3.1.1 代码混…

网站搭建从零开始(0)--域名的选择与解析

目录 确定用途 购买域名 使用可靠的注册商购买域名 想好域名关键词 检查域名是否可用 添加域名到购物车并完成购买 域名的解析 登录注册商账户 选择要配置的域名 进入DNS解析设置 添加DNS记录 保存配置 检查解析是否生效 提示 确定用途 在购买域名之前&#xf…