二分查找算法的Python实现(头歌教学实践平台)

2023-10-30

第1关:二分查找算法

任务描述

本关任务:编写代码实现二分查找算法。

相关知识

为了完成本关任务,你需要掌握: 1.查找的基本概念; 2.如何实现二分查找。

查找的基本概念

如果数据项被保存在如列表这样的集合中,我们会称这些数据项具有线性或者顺序关系。在 Python 的列表 List 中,这些数据项的存储位置称为下标(index),这些下标都是有序的整数。通过下标,我们可以按照顺序来访问和查找数据项,这种技术称为“顺序查找”。图 1 显示了顺序查找的基本过程,要确定列表中是否存在需要查找的数据项,首先从列表的第 1 个数据项开始,按照下标增长的顺序逐个比对数据项,如果到最后一个都未发现要查找的项,那么查找失败。

 图1 整数列表的顺序查找

要对查找算法进行分析,首先要确定其中的基本计算步骤。在查找算法中,这种基本计算步骤就是进行数据项的比对。比对当前数据项等于还是不等于要查找的数据项,比对的次数决定了算法的时间复杂度。在顺序查找算法中,为了保证讨论的是一般情形,需要假定列表中的数据项并没有按值排列顺序,在列表中各处出现的概率是相同的。对于具有 n 个数据项的列表,所查找的数据项是否在列表中,比对次数是不一样的。

  1. 如果数据项不在列表中,需要比对所有数据项才能得知,比对次数是 n。

  2. 如果数据项在列表中,其情况就较为复杂。最好的情况是第 1 次比对就找到,最坏的情况是要进行 n 次比对。

因为数据项在列表中各个位置出现的概率是相同的,平均状况下比对的次数是 n/2,所以顺序查找的时间复杂度是O(n)

以上我们是假定列表中的数据项是无序的,那么如果数据项排了序,顺序查找算法的效率又如何?在有序表中,当数据项存在时,比对过程与无序表完全相同。不同之处在于,如果数据项不存在,比对可以提前结束。图 2 展示了在有序表中顺序查找数据项 50 的过程,当看到 54 时,可知道后面不可能存在 50,可以提前退出查找。

图2 在有序表中进行顺序查找

实际上,对于有序表,顺序查找的算法复杂度仍然是O(n)。只是在数据项不存在的时候,有序表的查找能节省一些比对次数,但并不改变其数量级。

二分查找

那么对于有序表,有没有更好更快的查找算法?在顺序查找中,如果第 1 个数据项不匹配查找项的话,那最多还有 n-1 个待比对的数据项。为了提升查找效率,我们可以引入二分查找算法,利用有序表的特性,迅速缩小待比对数据项的范围。

二分查找的基本思路为:

设 R[first,…,last] 是当前的查找区间,首先确定该区间的中间位置为 mid=(first+last)/2,然后将待查的数据项 k 与 R[mid]进行比较:

  1. 若相等,则查找成功;

  2. 若 R[mid]>k,则由表的有序性可知 R[mid,…,last] 均大于 k,因此若表中存在该数据项,则一定是在 mid 左边的子表 R[first,…,mid-1] 中,故将其作为新的查找区间;

  3. 若 R[mid]<k,则由表的有序性可知 R[first,…,mid] 均小于 k,因此若表中存在该数据项,则一定是在 mid 右边的子表 R[mid+1,…,last] 中,故将其作为新的查找区间。

无论如何,我们都会将比对范围缩小到原来的一半,然后在新的比对范围中重复这个过程。图 3 展示了在有序表中如何使用二分查找方法快速找到值为 54 的项。首先将有序表中间的项 44 与 54 进行比较,44 比 54 小,则 54 在列表的后半部分,新的比对范围缩小为从 54 到 93 的部分。再将中间项 65 与 54 进行比较,65 比 54 大,则 54 在前半部分,新的比对范围缩小为从 54 到 55 的部分。再将中间项 54 与 所查找的项 54 进行比较,匹配成功,查找结束,总共比较 3 次。

图3 在有序表中进行二分查找

编程要求

在右侧编辑器中的 Begin-End 区间补充代码,根据二分查找的算法思想完成binarySearch函数,实现在有序表中查找数据项。若查找成功,返回 True;若查找失败,返回 False。

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确的数值,只有所有数据全部计算正确才能通过测试:

测试输入:

  1. 0,1,2,8,13,17,19,32,42

输入说明:输入为需要在其中查找的有序表。

预期输出:

  1. False
  2. False
  3. True
  4. False

输出说明:输出为在有序表中查找数据项 3、7、13、22 的查找结果。若查找成功,返回 True;若查找失败,返回 False。

测试输入:

  1. 2,5,7,9,13,22,30,47,50

预期输出:

  1. False
  2. True
  3. True
  4. True

开始你的任务吧,祝你成功!

'''请在Begin-End之间补充代码, 完成binarySearch函数'''

def binarySearch(alist, item):
    first = 0  # 查找范围第一项的下标
    last = len(alist)-1   # 查找范围最后一项的下标
    found = False

    while first<=last and not found:
        midpoint = (first + last)//2   # 中间项下标
        # 若列表alist的中间项与查找项item相等,则查找成功,found置为True
        # 否则就需要缩小比对范围,分为两种情况:
        # 1.查找项比中间项小,说明查找项在前半部分,更改last
        # 2.查找项比中间项大,说明查找项在后半部分,更改first
        # ********** Begin ********** #    
        if alist[midpoint]==item:            
            found=True        
        else:            
            if item<alist[midpoint]:                
                last=midpoint-1            
            elif item>alist[midpoint]:                
                first=midpoint+1    
        # ********** End ********** #

    return found

 


第2关:二分查找的递归实现

任务描述

本关任务:编写代码使用递归方法实现二分查找。

相关知识

为了完成本关任务,你需要掌握: 1.如何递归实现二分查找; 2.二分查找的算法分析。

递归实现二分查找

二分查找算法实际上体现了解决问题的典型策略:分而治之。该策略如图 1 所示,是将问题分为若干更小规模的部分,通过解决每一个小规模部分问题,并将结果汇总,从而得到原问题的解。

图1 分而治之的过程 

显然,递归算法就是一种典型的分治策略算法,二分查找也适合用递归算法来实现。当我们对一个列表执行二分查找时,我们首先选择中间项。如果查找项比中间项小,我们可以在原来列表的前半部分执行二分查找;同样地,如果查找项更大,我们可以在后半部分执行二分查找。无论怎样,这都是一个对较小的列表实现二分查找的递归调用。

二分查找的算法分析

由于二分查找每次比对都将下一步的比对范围缩小一半,对于 n 个数据项的有序表,比对范围会逐渐减半到 n/2n/4n/8……n/2^{i}。当比对次数足够多以后,比对范围内就会仅剩余 1 个数据项,且无论这个数据项是否匹配查找项,比对最终都会结束。根据等式n/2^{i}=1可求得 i 的值,所以二分法查找的时间复杂度是O(logn)

另外,虽然二分查找在时间复杂度上优于顺序查找,但也要考虑到对数据项进行排序的开销。如果数据集经常变动,查找次数相对较少,那么可能直接对无序表进行顺序查找要更经济。所以,在算法的选择问题上,光看时间复杂度的优劣是不够的,还需要考虑到实际应用的情况。

编程要求

根据提示,在右侧编辑器中的 Begin-End 区间补充代码,完成binarySearch函数,使用递归的方式来对有序表实现二分查找。若查找成功,返回 True;若查找失败,返回 False。

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确的数值,只有所有数据全部计算正确才能通过测试:

测试输入:

  1. 0,1,2,8,13,17,19,32,42

输入说明:输入为需要在其中查找数据项的有序表。

预期输出:

  1. True
  2. True
  3. True
  4. False

输出说明:输出为在有序表中查找数据项 2、8、13、30 的查找结果。若查找成功,返回 True;若查找失败,返回 False。

测试输入:

  1. 2,5,7,9,13,22,30,47,50

预期输出:

  1. True
  2. False
  3. True
  4. True

提示

  1. list = [0, 1, 2, 3, 4, 5, 6]
  2. print(len(list)//2)
  3. print(list[:3])
  4. print(list[4:])

输出:

  1. 3
  2. [0, 1, 2]
  3. [4, 5, 6]

开始你的任务吧,祝你成功!

'''请在Begin-End之间补充代码, 完成binarySearch函数'''

def binarySearch(alist, item):
    if len(alist) == 0:  # 递归的基本结束条件
        return False
    else:
        midpoint = len(alist)//2
        if alist[midpoint]==item:
          return True
        else:   # 缩小规模
            # 若查找项小于中间项,则需要递归调用自身来实现对前半部分(从最开始到中间)的查找,返回递归的结果
            # 否则查找项大于中间项,则需要递归调用自身来实现对后半部分(从中间到最后)的查找,返回递归的结果
            # ********** Begin ********** #    
            if item<alist[midpoint]:
                return binarySearch(alist[:midpoint],item)
            elif item>alist[midpoint]:
                return binarySearch(alist[midpoint+1:],item)
            # ********** End ********** #

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

二分查找算法的Python实现(头歌教学实践平台) 的相关文章

  • Python 中的字节数组

    如何在 Python 中表示字节数组 如 Java 中的 byte 我需要用 gevent 通过网络发送它 byte key 0x13 0x00 0x00 0x00 0x08 0x00 在Python 3中 我们使用bytes对象 也称为s
  • Python有条件求解时滞微分方程

    我在用dde23 of pydelay包来求解延迟微分方程 我的问题 如何有条件地编写方程 例如目标方程有两个选项 when x gt 1 dx dt 0 25 x t tau 1 0 pow x t tau 10 0 0 1 x othe
  • Kivy - 文本换行工作错误

    我正在尝试在 Kivy 1 8 0 应用程序中换行文本 当没有太多文字时 一切正常 但如果文本很长并且窗口不是很大 它只是剪切文本 这是示例代码 vbox BoxLayout orientation vertical size hint y
  • for 循环如何评估其参数

    我的问题很简单 Does a for循环评估它每次使用的参数 Such as for i in range 300 python 是否会为此循环的每次迭代创建一个包含 300 个项目的列表 如果是的话 这是避免这种情况的方法吗 lst ra
  • 使用 Django Rest 保存 Base64ImageField 类型会将其保存为原始图像。如何将其转换为普通图像

    我的模型中有 5 个图像字段 imageS imageS imageS imageS 和 imageE 我正在尝试按以下方式保存图像 图像的类型Base64ImageField images imageA imageB imageC ima
  • 了解 Python 中的酸洗

    我最近接到一项作业 需要以腌制形式放置一本字典 其中每个键引用一个列表 唯一的问题是我不知道腌制形式是什么 谁能给我指出一些好的资源的正确方向来帮助我学习这个概念 pickle 模块实现了一个基本但强大的算法 用于序列化和反序列化 Pyth
  • 当单词以“|”分隔时如何读取文件(埃因霍温)?

    在Python中 我有一个文件 其中的单词由 例如 city state zipcode 我的文件阅读器无法区分单词 另外 我希望我的文件阅读器从第 2 行而不是第 1 行开始 如何让我的文件阅读器分隔单词 import os import
  • 如何将 self 传递给装饰器?

    我该如何通过self key下面进入装饰器 class CacheMix object def init self args kwargs super CacheMix self init args kwargs key func Cons
  • python 中的 Johansen 协整检验

    我找不到任何有关在处理统计和时间序列分析 pandas 和 statsmodel 的 Python 模块中执行 Johansen 协整检验的功能的参考 有谁知道是否有一些代码可以执行时间序列之间的协整测试 现在 这已在 Python 的 s
  • PySide6.1 与 matplotlib 3.4 不兼容

    当我只安装PySide6时 GUI程序运行良好 但是一旦我安装了matplotlib及其依赖包 包括pyqt5 则GUI程序将无法运行并输出以下错误消息 This application failed to start because no
  • `list()` 被认为是一个函数吗?

    list显然是内置类型 https docs python org 3 library stdtypes html list在Python中 我看到底下有一条评论this https stackoverflow com a 53645813
  • 如何使用 paramiko 查看(日志)文件传输进度?

    我正在使用 Paramiko 的 SFTPClient 在主机之间传输文件 我希望我的脚本打印文件传输进度 类似于使用 scp 看到的输出 scp my file user host user host password my file 1
  • Python 声音(“铃声”)

    我想让一个 python 程序在完成任务时通过发出嘟嘟声来提醒我 目前 我使用import os然后使用命令行语音程序说 进程完成 我更愿意它是一个简单的 铃 我知道有一个函数可以用于Cocoa apps NSBeep 但我认为这与此没有太
  • 无法在 python 3.8 上将带有 webapp 的 python 部署到 azure

    我正在尝试使用部署一个测试项目Flask使用以下方法将框架迁移到 Azure 云中Azure CLI https learn microsoft com en us azure app service containers quicksta
  • 对数据帧的每 2 小时数据进行 Groupby

    我有一个数据框 Time T201FN1ST2010 T201FN1VT2010 1791 2017 12 26 00 00 00 854 69 0 87 1792 2017 12 26 00 20 00 855 76 0 87 1793
  • 为什么 smtplib.SMTP().sendmail 不发送 DKIM 签名邮件

    我已经在服务器上设置了 postfix 以及 openDKIM 当我跑步时 echo Testing setup mail s Postfix test my email address 我收到电子邮件 邮件标题中有一个DKIM Signa
  • 如何循环遍历字典列表并打印特定键的值?

    我是 Python 新手 有一个问题 我知道这是一个非常简单的问题 运行Python 3 4 我有一个需要迭代并提取特定信息的列表 以下是列表 称为部分 的示例 已截断 数千个项目 state DEAD id phwl type name
  • 在 Django shell 会话期间获取 SQL 查询计数

    有没有办法打印 Django ORM 在 Django shell 会话期间执行的原始 SQL 查询的数量 Django 调试工具栏已经提供了此类信息 例如 5 QUERIES in 5 83MS但如何从 shell 中获取它并不明显 您可
  • 如何获取所有mysql元组结果并转换为json

    我能够从表中获取单个数据 但是当我试图获取表上的所有数据时 我只得到一行 cnn execute sql rows cnn fetchall column t 0 for t in cnn description for row in ro
  • 缓存 Flask-登录 user_loader

    我有这个 login manager user loader def load user id None return User query get id 在我引入 Flask Principal 之前它运行得很好 identity loa

随机推荐

  • Gentle Jena【2020 年 “联想杯” G题】【笛卡尔树/单调栈】

    题目链接 题意 给你N个数 b 1 b n 但是不是一开始就给出的 一开始只给出b 1 后面的都是通过前面的情况得到的 给出p x y z和b 1 p x y z都是涉及b 2 b n 怎样来的 我们定义一个B S 还有 而其中A i 是代
  • PostgreSQL的基本使用整理

    我是目录 1 数据库操作 2 表操作 3 Schema 模式 4 如何备份PG数据库 5 用户操作 6 常用命令总结 1 数据库操作 1 创建数据库 create database mydb 2 查看所有数据库 list 或 l 3 切换当
  • [网络安全提高篇] 一一九.恶意软件动态分析经典沙箱Cape的安装和基础用法详解

    终于忙完初稿 开心地写一篇博客 网络安全提高班 新的100篇文章即将开启 包括Web渗透 内网渗透 靶场搭建 CVE复现 攻击溯源 实战及CTF总结 它将更加聚焦 更加深入 也是作者的慢慢成长史 换专业确实挺难的 Web渗透也是块硬骨头 但
  • Flask 项目用到的插件和技术

    项目地址 https github com laoqiu pypress 作者 老秋 老秋是05年开始从事前端设计的设计师 于07年喜欢上python 目前从事python项目开发 学习并使用过一些流行框架 如django webpy fl
  • 不到 20 人的 IT 公司该去吗?

    周末就不分享技术了 今天早上在知乎看到一个挺有意思的话题 不到 20 人的 IT 公司该去吗 回答区有一位老哥分享了自己在一个20 来人的小公司的奇葩工作经历 分享一下 下面是正文 刚到西安有幸加入了一个 20 来人的 it 公司 本来是不
  • 教育大数据总体解决方案(1)

    目录 一 方案背景 1 1 以教育现代化支撑国家现代化 1 2 教育信息化是教育现代化重要内容和标志 1 3 大数据驱动教育信息化发展 1 4 政策指导大数据推动教育变革 1 5 教育大数据应用生态服务教育现代化 二 建设需求 2 1 地区
  • 二叉树的最大深度C++

    Definition for a binary tree node struct TreeNode int val TreeNode left TreeNode right TreeNode int x val x left NULL ri
  • 使用HTTP爬虫ip中的常见误区与解决方法

    在如今的互联网时代 为了保障个人隐私和实现匿名浏览 许多人选择使用HTTP爬虫ip 然而 由于缺乏了解和使用经验 常常会出现一些误区 本文将为大家介绍使用HTTP爬虫ip过程中常见的误区 并提供相应的解决方法 帮助大家更好地使用HTTP爬虫
  • 用赋值代替 protobuf CopyFrom()

    用赋值代替 protobuf CopyFrom 示例 Replace protobuf CopyFrom with assignment protobuf 生成的 C 代码中 因为 CopyFrom 可以接受任何 Message 作为参数
  • 都2023年啦~用python来玩一次股票.....

    人生苦短 我用python 这不是2023年已经来了吗 总不能空着手回去吧 这次简单用python来玩一下股票 本章源码 更多电子书点击文末名片 准备工作 我们需要使用这些模块 通过pip安装即可 后续使用的其它的模块都是Python自带的
  • HttpRunner3.x(6)参数化数据驱动

    在进行接口测试时 有时候需要给一个接口传入多组数据 这时候就会用到参数化数据驱动 HttpRunner v3 x开始 测试用例和测试用例集都可以实现参数化数据驱动 需要使用parameters关键字 定义参数名称并指定数据源取值方式 数据源
  • 开源的7大理念

    点击上方 开源社 关注我们 作者 卫剑钒 编辑 Corrie 软件正在慢条斯理地吞噬世界 开源正在慢条斯理地吞噬软件业 软件正在吞噬世界 是的 对于购物 吃饭 健身 交停车费都需要使用软件的年代 对于平均每人每天都要花费5到6个小时使用手机
  • 字节流文件读取

    import java io public class Test public static void main String args try 源文件 FileInputStream inputStream new FileInputSt
  • 初步了解ES

    一 ES基础查询 1 es基础查询 1 1 准备数据 准备数据 PUT test index doc 1 name 顾老二 age 30 from gu desc 皮肤黑 武器长 性格直 tags 黑 长 直 PUT test index
  • 39条常见的Linux系统简单面试题

    本文系转载 原文链接 http www cnblogs com chengjian physique p 8313175 html 1 如何看当前Linux系统有几颗物理CPU和每颗CPU的核数 答 root centos6 10 55 3
  • CAN记录仪应用—如何实现特种车辆远程数据监控

    在目前生活中 路边随处可以看到一些特种车辆 比如洒水车 消毒车等 在大家看不到的领域种 特种车在一些条件艰苦的条件下也发挥着重要的作用 比如掘进车 矿下防爆车 那么工作人员如何远程获得车辆的数据呢 来可电子提供可靠的解决方案 车联网综合网关
  • vue移动端绑定click事件失效问题

    原因是使用了better scroll 它会阻止touch事件 所以在配置中需要加上click true 例 this scroll new BScroll this refs search click true
  • 彩条发生模块(verilog)

    像素时钟输入 1280x720 60P的像素时钟为74 25MHz Description 彩条发生模块
  • 跨境电商如何防关联?关联因素有哪些?

    相信许多想要入局跨境电商小伙伴都遇到 防关联 的难题 想要在跨境路上驰骋无阻 那你一定不能忽略各平台的多账号防关联问题 下面小编为大家介绍 我的实操解决防关联的经验 往下看 通常防关联需要从以下因素进行考虑 1 浏览器指纹 当我们在网络上浏
  • 二分查找算法的Python实现(头歌教学实践平台)

    第1关 二分查找算法 任务描述 本关任务 编写代码实现二分查找算法 相关知识 为了完成本关任务 你需要掌握 1 查找的基本概念 2 如何实现二分查找 查找的基本概念 如果数据项被保存在如列表这样的集合中 我们会称这些数据项具有线性或者顺序关