编程中的宝藏:二分查找

news2024/11/26 12:43:57

二分查找

假设你需要在电话簿中找到一个以字母 “K” 开头的名字(虽然现在谁还在用电话簿呢!)。你可以从头开始翻页,直到进入以 “K” 打头的部分。然而,更明智的方法是从中间开始,因为你知道以 “K” 打头的名字很可能在电话簿的中间部分。

类似地,当你要在字典中查找一个以字母 “O” 开头的单词时,你也会从中间附近开始搜索。

再举一个例子,当你登录 Facebook 时,系统需要核实你是否有该网站的账户。它必须在数据库中查找你的用户名。如果你的用户名是 “karlmageddon”,Facebook 可以从以字母 “A” 开头的部分开始查找。然而,更聪明的做法是从中间开始查找。

这些场景都涉及到查找问题,而在所有这些情况下,都可以使用同一种算法来解决,那就是二分查找

二分查找是一种算法,它的输入是一个有序元素列表(必须有序的原因稍后解释)。如果要查找的元素包含在列表中,二分查找会返回其位置;否则返回 -1。

下面的示例演示了二分查找的工作原理。我们随意选择一个在 1 到 100 之间的数字。

Binary Search Example

你的目标是以最少的猜测次数猜到这个数字。每次猜测后,我会告诉你是小了、大了还是猜对了。如果你从 1 开始顺序猜测,过程可能是这样的:

  • 猜测 1 -> 小了
  • 猜测 2 -> 小了
  • 猜测 3 -> 小了

这种方法被称为简单查找,更确切地说是傻找。每次猜测只能排除一个数字。如果数字是 99,你最多需要猜测 99 次才能猜对。

更聪明的查找方法

下面是一种更聪明的猜测方法:从 50 开始。

  • 猜测 50 -> 小了,但排除了一半的数字!现在你知道 1 到 50 都是小了。接下来,你猜 75。
  • 猜测 75 -> 大了,又排除了一半的数字!使用二分查找,你猜测的是中间的数字,从而每次都可以排除一半的数字。然后,你猜测 63(50 和 75 之间的数字)。

这就是二分查找,你刚刚学会了一种全新的算法!每次猜测都会排除一半的数字,如下图所示:

Binary Search Steps

不论我心里想的是哪个数字,你最多需要 7 次猜测就能找到,因为每次猜测都会排除很多数字。对比一下:

  • 简单查找:100 步
  • 二分查找:7 步

也许在使用者的角度看,这 97 步的差距似乎微不足道。然而,随着元素数量的增加,二分查找的优势会越来越明显。

现在,让我们考虑一个问题:如果你要在包含 240,000 个单词的字典中查找一个单词,最多需要多少步?假设要查找的单词位于字典的末尾,使用简单查找将需要 240,000 步。而如果使用二分查找,每次都会排除一半的单词,直到最后只剩下一个单词。

在进行二分查找时,每次排除的单词数量是通过将搜索范围减半来计算的。因为字典中有 240,000 个单词,每次排除一半,我们可以计算出每次排除的单词数量,如下:

  • 初始范围:240,000 个单词
  • 第 1 次排除:120,000 个单词
  • 第 2 次排除:60,000 个单词
  • …(后续步骤省略)

因此,使用二分查找,最多需要 18 次排除就能找到一个特定单词,即使在包含 240,000 个单词的字典中。这是因为每一次排除一半的单词,使得搜索范围迅速减小,直到只剩下一个单词。

仅当列表是有序的时候,二分查找才适用。例如,电话簿中的名字按字母顺序排列,因此可以使用二分查找来查找名字。

运行时间

让我们再次回到二分查找。使用二分查找相比于简单查找能节省多少时间呢?简单查找是逐个地检查数字,如果列表包含 100 个数字,最多需要猜测 100 次。而如果列表包含 40 亿个数字,最多需要猜测 40 亿次。换句话说,最多需要的猜测次数与列表的长度相同,这种情况被称为线性时间(linear time)

然而,二分查找则不同。如果列表包含 100 个元素,最多只需猜测 7 次;如果列表包含 40 亿个数字,最多只需猜测 32 次。相比之下,二分查找的运行时间是对数时间(logarithmic time)

下表总结了我们所发现的情况:

Comparison

总结

​ 当我们进一步探讨二分查找和简单查找之间的差异时,不难发现,二分查找的性能优势随着元素数量的增加变得更加显著。虽然在开始时,二分查找的速度提升可能并不明显,但随着列表规模的增长,它的优越性将愈发凸显出来。

​ 简单查找以线性时间的方式进行,每增加一个元素,它需要的额外时间也会线性增长。这就导致当元素数量庞大时,每次查找都会变得耗时且不实际。例如,如果你有一个拥有数百万个元素的数据集,使用简单查找进行查询可能会变得极其缓慢,甚至不切实际。然而,二分查找以对数时间的方式运作,每次查找只需要排除一半的元素。

​ 这意味着,尽管数据量增加,每次查找所需的额外时间增长得非常缓慢。就像是在探索一个迷宫时,你只需每次选择一个正确的路径,逐渐逼近目标,而不是逐一检查所有可能的路径。

​ 这种对数级别的优越性意味着,在大数据集或者长列表中,二分查找的速度几乎不会受到影响。它的查询速度可以在常数时间内保持,无论数据规模如何增长。而这也是为什么在现代计算机科学中,二分查找是一种备受推崇的高效算法。

​ 因此,无论是在简单的名字查找、大规模数据处理,还是搜索庞大的字典中的单词,二分查找都是一种强大的工具,能够在海量信息中快速找到目标。在信息爆炸的今天,掌握并充分利用这种高效的算法,对于优化搜索效率、提升数据处理速度至关重要。

代码示例

Python

def binary_search(lst, item):
    left = 0
    right = len(lst) - 1
    while left <= right:
        # 你每次都检查中间的元素。
        mid = (left + right) // 2
        val = lst[mid]
        if val == item:
            return mid
        if val > item:
            # 如果猜的数字大了,就修改right
            right = mid - 1
        else:
            # 如果猜的数字小了,就相应地修改left。
            left = mid + 1
    return -1  # Return -1 if item is not found

my_list = [1, 2, 3, 4, 5, 6, 7, 8]

print(binary_search(my_list, 6))

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) / 2;
            int val = arr[mid];
            if (val == target) {
                return mid;
            }
            if (val > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] myArray = {1, 2, 3, 4, 5, 6, 7, 8};
        int searchItem = 6;
        int result = binarySearch(myArray, searchItem);
        System.out.println(result);
    }
}

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

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

相关文章

【深度学习】多粒度、多尺度、多源融合和多模态融合的区别

多粒度&#xff08;multiresolution&#xff09;和多尺度&#xff08;multiscale&#xff09; 多粒度&#xff08;multiresolution&#xff09;和多尺度&#xff08;multiscale&#xff09;都是指在不同的空间或时间尺度上对数据或信号进行分析和处理。其中 多尺度&#xff1…

代码审计-Thinkphp框架审计前置知识点

代码审计必备知识点&#xff1a; 1、代码审计开始前准备&#xff1a; 环境搭建使用&#xff0c;工具插件安装使用&#xff0c;掌握各种漏洞原理及利用,代码开发类知识点。 2、代码审计前信息收集&#xff1a; 审计目标的程序名&#xff0c;版本&#xff0c;当前环境(系统,中间件…

接口测试实战,Jmeter正则提取响应数据-详细整理,一篇打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 在测试时&#xf…

Linux 编译CEF源码详细记录

Linux CEF&#xff08;Chromium Embedded Framework&#xff09;源码下载编译 背景 由于CEF默认的二进制分发包不支持音视频播放&#xff0c;需要自行编译源码&#xff0c;将ffmpeg开关打开才能支持。这里介绍的是Linux平台下的CEF源码下载编译过程。 Windows平台参考&#…

营收、净利同比微增,喜临门品牌升级“临门一脚”?

8月8日晚&#xff0c;喜临门发布2023上半年业绩报告。根据财报&#xff0c;2023年上半年&#xff0c;喜临门营业收入约38.05亿元&#xff0c;同比增加5.53%&#xff1b;归属于上市公司股东的净利润约2.22亿元&#xff0c;同比增加1.2%。 如果仅从这份财报看&#xff0c;喜临门…

高忆管理:“T+0”或带来市场波动

据了解&#xff0c;各地区对日内“T0”买卖&#xff0c;制定了不同的约束和监督办法。如美国不同账户类型监管、日本的特别涨跌停准则和日内单次“T0”、印度组织投资者禁入和特别保证金准则、中国台湾从信用账户到现股账户逐渐放开“T0”准则等。 上海高忆私募基金&#xff08…

软件的帮助文档应该怎么做?

在当今数字化时代&#xff0c;软件已经成为我们生活和工作中不可或缺的一部分。然而&#xff0c;对于用户来说&#xff0c;使用新的软件可能会面临一些挑战。这时&#xff0c;一个好的软件帮助文档就显得尤为重要了。软件帮助文档是一种向用户提供指导、解答问题和提供支的文件…

图像单幅或多幅展示(OPENCV-python)

# -*- coding: utf-8 -*- import cv2print("---------------------------------单幅图像读取-----------------------------") # 打印opencv版本 print(cv2.version.opencv_version) # 图像读取 img cv2.imread(Figure_1.png) if img is None:print(Image read erro…

保姆级Arcgis安装图文安装教程

参考视频&#xff1a;【钟老师arcGIS从放弃到入门】02软件下载与安装_哔哩哔哩_bilibili 安装包在视频简介中有 注释&#xff1a;安装过程中有犯错误&#xff0c;请耐心看完一遍再跟着操作 &#xff08;一&#xff09;安装包下载 下载视频中分享的压缩包(压缩包密码&#x…

【UE4 RTS】07-Camera Boundaries

前言 本篇实现的效果是当CameraPawn移动到地图边缘时会被阻挡。 效果 步骤 1. 打开项目设置&#xff0c;在“引擎-碰撞”中&#xff0c;点击“新建Object通道” 新建通道命名为“MapBoundaries”&#xff0c;然后点击接受 2. 向视口中添加 阻挡体积 调整阻挡体积的缩放 向四…

【巧妙继承】C++玩转继承的神级技巧

本篇目录 什么是继承&#xff1f;继承的格式继承关系和访问限定符继承父类成员访问方式的变化基类和派生类对象赋值转换继承中的作用域派生类的默认成员函数构造函数拷贝构造赋值重载析构函数 继承与友元继承与静态成员多继承与菱形继承虚拟继承菱形虚拟继承的实现原理 继承和组…

DPMFoam给粒子添加周期性边界条件

问题引入 DPMFoam是OpenFOAM中的一个颗粒两相流求解器&#xff0c;在流体的运算中&#xff0c;我们经常采用周期性边界条件&#xff0c;在OpenFOAM中即为cyclic&#xff0c;那么对于颗粒&#xff0c;能否在边界也设置成周期性边界呢&#xff0c;在CFDEM中是可以的&#xff0c;…

使用C#加载TOOLBLOCK

前言 因为Vpp文件类型包含了以下三种 QuickBuidJobToolBlock 不同类型的打开方式不同&#xff0c;需要提前知道vpp是什么类型 例如 这个TB.vpp文件是TOOLBLOCK&#xff0c;就不能直接在visionpro中打开&#xff08;直接打开需要QuickBuid文件&#xff09;&#xff0c; 可以…

明道云联合EMQ基于IIoT场景技术白皮书

背景介绍 智能物联网设备在IIoT场景中有着广泛的应用&#xff0c;但如何管理和监控这些设备是一个挑战。为了解决这个问题&#xff0c;用户首先需要采集各项设备基础数据&#xff0c;然后在此基础上通过业务系统管理设备。 EMQ作为数据链接底座&#xff0c;可提供高可靠、高性…

ROS入门-第 1 章 ROS概述与环境搭建

目录 第 1 章 ROS概述与环境搭建 1.1 ROS简介 1.1.1 ROS概念 1.1.2 ROS设计目标 1.1.3 ROS发展历程 1.3 ROS快速体验 1.3.1 HelloWorld实现简介 1.3.2 HelloWorld&#xff08;C版&#xff09; 步骤 1&#xff1a;创建工作空间 步骤 2&#xff1a;创建发布者节点 步骤…

python——案例16:约瑟夫生者死者链队列

约瑟夫游戏的大意是&#xff1a;一条船上有30个人&#xff0c;因为在海上遇到风暴 因此船长告诉乘客&#xff0c;必须牺牲15个人&#xff0c;并议定30个人围成一圈&#xff0c; 由第一个人数起&#xff0c;依次报数&#xff0c;数到第9人&#xff0c;便把他投入大海中&#xff…

Multimap用法详解

Multimap Multimap 是 Google 的 Guava 库为 Java 引入的一种新集合类型&#xff0c;它允许将多个值存储在单个键下。它被设计为一种替代 Map<K, List> 或 Map<K, Set>&#xff08;JDK 标准集合框架&#xff09;的方案。 Multimap<K, V> 扩展了 AbstractMul…

性能测试基础了解

什么是线程&#xff1f; 线程是程序中的一个执行流&#xff0c;每个线程都有自己的专有寄存器(栈指针、程序计数器等)&#xff0c;但代码区是共享的&#xff0c;即不同的线程可以执行同样的函数。 一般在性能测试过程中&#xff0c;我们认为一个线程就是一个虚拟用户。 什么…

【CSS】背景图定位问题适配不同机型

需求 如图, 实现一个带有飘带的渐变背景 其中头像必须显示飘带凹下去那里 , 需要适配不同的机型, 一不下心容易错位 实现 因为飘带背景是版本迭代中更新的, 所以飘带和渐变背景实则两个div 飘带切图如下 , 圆形部分需要契合头像 <view class"box-bg"><…

json-server的入门

由于前端开发的时候&#xff0c;需要向后端请求数据&#xff0c;有的时候后端还没有准备好&#xff0c;所以需要使用一些简单的静态数据&#xff0c;但是我们更加希望能够模拟请求以及请求回来的过程&#xff0c;这个时候就需要使用json-server Json-Server的介绍 json-server…