二分查找【详解】

news2024/12/23 1:32:26

在这里插入图片描述

本期介绍🍖
主要介绍:二分查找的简单思路,为什么必须在有序的前提下才能使用二分查找,该怎么用C程序来实现二分查找,二分查找的局限性👀。


文章目录

  • 1. 题目
  • 2. 思路
  • 3. 前提条件
  • 4. 编写程序


1. 题目

  在一个有序的数组中查找一个数,如果找到该数则返回下标,如果没有找到就返回没有找到。


2. 思路

  当我们要从一个序列中查找一个元素的时候,最快想到的方法就是顺序查找法(即:从前到后依次查找)。但这种方法过于无脑,就是暴力的把每个元素都排查一遍。元素个数少的时候还行,一旦元素个数多起来,效率是非常低下,所以在实际中这种查找的方法是被摒弃的。
  这里就不得不介绍一种简单且效率较高的查找方法了:二分查找法,又称折半查找法。但该方法是建立在有序的前提下的,基本思路就是:先找到那个有序序列的中间元素mid,然后拿它和要找的元素K进行比较,就可以初步判断K所在范围,既然查找范围已确定,自然该范围之外的元素就可以不用再查找了。
  因为二分查找每一次查找都可以缩减掉一半的查找范围,由此可以知道二分查找法的时间复杂度: log ⁡ 2 ( N ) \log_2(N) log2(N)。举个例子来解释该时间复杂度:若这里一共有2^32个元素,那么我在最坏的情况下也只需要32次就可以找到我想找的元素;而顺序查找法最坏的情况下,却需要查找 4,294,967,296‬ 次!!!,可见二分查找法的效率是非常之高的。


3. 前提条件

  都说二分查找法的前提条件是:查找的序列必须是有序的。我想大概很多小伙伴都会错误的认为有序是差值恒为1的顺序数列(就像这样1、2、3、4、5、6、7、8、9)。这只不过是有序的某一种情况罢了,那何为有序呢?即:该序列中的所有元素都是按照升序或者降序排列好的,元素与元素只间的差值虽然是随机的,但始终是在递增或递减(例如这样一个序列:3、12、24、31、46、48、66、79、82)。


4. 编写程序

  上面介绍完二分查找的思路和其限制条件后,接下来就该讲一讲如何去实现代码了。就用该案来讲解吧,下图所示序列中查找数字7,看是否能找到。
在这里插入图片描述

1. 第一步👀

首先,我们是要在一个有序的序列中查找某个元素的,那么该序列就必须有个连续的存储空间来存放,所以我们想到了用数组arr来存放。

#include<stdio.h>
int main()
{
	//存储递增的有序数列
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
}

2. 第二步👀

接下来,就该是找到序列的中间元素了,那该怎么找?我提供一个思路:通过对数组元素下标的计算来找到中间元素(中间元素下标mid=(数组最左边下标left + 最右边元素下标right)/ 2)。
在这里插入图片描述
程序如下所示:

#include<stdio.h>
int main()
{
	
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//存储递增的有序数列
	int sz = sizeof(arr) / sizeof(arr[0]);//sz是数组元素的总个数
	int mid = 0;//存储中间元素的下标
	
	//左、右元素下标确定了被查找元素k的所在范围
	int left = 0;//最左边元素的下标
	int right = sz - 1;//最右边元素的下标
	int k = 0;//所要查找的元素k
	scanf("%d", &k);
	
	mid = (left + right) / 2;//计算中间元素的下标
}

3. 第三步👀

然后就拿中间元素和所查找元素k进行比较(这里我设置k = 7),发现7 > 5(中间元素),所以可以重新精确k的范围在中间元素之后了即:最左边元素应该为中间元素后面一个(left = mid + 1),最右边元素下标right不变。
在这里插入图片描述
但其他的情况也不能忽略,k < mid时范围重新精确到了mid的左半部分,就是(right = mid - 1),left不变;还有当k = mid时就意味着:找到所要找的那个数了,就是mid下标所对应的那个数。程序如下:

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//存储递增的有序数列
	int sz = sizeof(arr) / sizeof(arr[0]);//sz是数组元素的总个数
	int mid = 0;//存储中间元素的下标

	//左、右元素下标确定了被查找元素k的所在范围
	int left = 0;//最左边元素的下标
	int right = sz - 1;//最右边元素的下标
	int k = 0;//所要查找的元素k
	scanf("%d", &k);

	mid = (left + right) / 2;//计算中间元素的下标
	//判断mid和看大小,重新精确k所在范围
	if (arr[mid] < k)
	{
		left = mid + 1;
	}
	else if (arr[mid] > k)
	{
		right = mid - 1;
	}
	else
	{
		printf("找到了\n");
	}
}

4. 第四步👀

然后就是重复的去执行:找中间元素下标,比较mid和k大小,从而更新迭代k新的范围,直到mid = k(即找到k了)为止。既然要实现重复的循环,程序中自然就要用到循环体了呀,那就加进去一个循环嘛。写道这里可还没算完呢,我们循环条件是什么还没确定呢!那循环条件如何确定呢?先思考个问题:若一直没找到我们所要找的元素,程序会以怎样的方式结束呢?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思考后我们发现在查找一个元素的时候,left下标和right下标会越来越靠近,甚至会指向一处,这个过程中left始终在right的左边(即:left <= right)。但如果一直找不到那个元素,两个下标必然会相互交错(即: left > right),这时循环结束。所以循环条件总结下来就是:while(left <= right)

程序最终完成,如下所示:

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//存储递增的有序数列
	int sz = sizeof(arr) / sizeof(arr[0]);//sz是数组元素的总个数
	int mid = 0;//存储中间元素的下标

	//左、右元素下标确定了被查找元素k的所在范围
	int left = 0;//最左边元素的下标
	int right = sz - 1;//最右边元素的下标
	int k = 0;//所要查找的元素k
	printf("请输入所要查找的数:");
	scanf("%d", &k);

	while (left <= right)
	{
		mid = (left + right) / 2;//计算中间元素的下标
	//判断mid和看大小,重新精确k所在范围
		if (arr[mid] < k)
		{
			left = mid + 1;
		}
		else if (arr[mid] > k)
		{
			right = mid - 1;
		}
		else
		{
			break;
		}
	}
	if (left > right)
		printf("没有找到该数\n");
	else
	{
		printf("找到了\n");
	}
}

程序执行结果如下:
在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀。

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

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

相关文章

Android Studio开发项目——记账簿应用

项目资源&#xff1a; 百度网盘链接&#xff1a;https://pan.baidu.com/s/1zN9lrIypi1t_QpuoBcdBNQ?pwdxj5h 提取码&#xff1a;xj5h 项目设计内容 1.基本功能描述 电子记账本是一种在线财务管理工具&#xff0c;用于帮助用户记录和管理他们的收入与支出。以下是电…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的水果新鲜程度检测系统(深度学习模型+UI界面代码+训练数据集)

摘要&#xff1a;开发水果新鲜程度检测系统对于提高农业产量和食品加工效率具有重大意义。本篇博客详细介绍了如何利用深度学习构建一个水果新鲜程度检测系统&#xff0c;并提供了完整的实现代码。该系统基于强大的YOLOv8算法&#xff0c;并结合了YOLOv7、YOLOv6、YOLOv5的对比…

ChatGPT 结合实际地图实现问答式地图检索功能基于Function calling

ChatGPT 结合实际地图实现问答式地图检索功能基于Function calling ChatGPT结合实际业务&#xff0c;主要是研发多函数调用&#xff08;Function Calling&#xff09;功能模块&#xff0c;将自定义函数通过ChatGPT 问答结果&#xff0c;实现对应函数执行&#xff0c;再次将结果…

打卡学习kubernetes——了解kubernetes组成及架构

目录 1 什么是kubernetes 2 kubernetes组件 3 kubernetes架构 1 什么是kubernetes kubernetes是一个旨在自动部署、扩展和运行应用容器的开源平台。目标是构建一个生态系统&#xff0c;提供组件和工具以减轻在公共和私有云中运行应用程序的负担。 kubernetes是&#xff1a…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的跌倒检测系统详解(深度学习模型+UI界面代码+训练数据集)

摘要&#xff1a;本研究介绍了一个基于深度学习和YOLOv8算法的跌倒检测系统&#xff0c;并对比分析了包括YOLOv7、YOLOv6、YOLOv5在内的早期版本性能。该系统可在多种媒介如图像、视频文件、实时视频流中准确识别跌倒事件。文内详解了YOLOv8的工作机制&#xff0c;并提供了相应…

一套plm系统大约多少钱?彩虹PLM系统

一套PLM&#xff08;产品生命周期管理&#xff09;系统的价格因多个因素而异&#xff0c;包括企业规模、需求复杂性、系统功能、技术支持和厂商选择等。一般来说&#xff0c;面向小型和微型企业的PLM产品&#xff0c;其价位在5万元~15万元左右&#xff1b;面向中型企业的中端PL…

STM32---通用定时器(二)相关实验

写在前面&#xff1a;前面我们学习了基本定时器、通用定时器的相关理论部分&#xff0c;了解到通用定时器的结构框图&#xff0c;总共包含六大模块&#xff1a;时钟源、控制器、时基单元、输入捕获、公共部分以及输出捕获。对相关模块的使用也做详细的讲解。本节我们主要是对上…

力扣刷题日记——L724. 寻找数组的中心下标

1. 前言 今天是力扣刷题日记的第二天&#xff0c;今天依旧是一道简单题啊&#xff0c;慢慢来&#xff0c;先看看题目是什么吧。 2. 题目描述 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和…

数据结构入门(3)顺序表和链表

1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一条直…

汤唯短发造型:保留经典和适合自己的风格,也许才是最重要的

汤唯短发造型&#xff1a;保留经典和适合自己的风格&#xff0c;也许才是最重要的 汤唯短发造型登上Vogue四月刊封面&#xff0c;引发网友热议。#李秘书讲写作#说说是怎么回事&#xff1f; 这次Vogue四月刊的封面大片&#xff0c;汤唯以一头短发亮相&#xff0c;身穿五颜六色的…

Python笔记:函数

Python函数定义规则&#xff1a; 函数代码块以def关键词开头&#xff0c;后接函数标识符名称和圆括号()。任何传入参数和自变量必须放在圆括号中间&#xff0c;圆括号之间可以用于定义参数。return [表达式] 结束函数&#xff0c;选择性地返回一个值给调用方&#xff0c;不带表…

力扣(LeetCode)142.环形链表 II

本博客讲解一道以前大厂面试常考的链表oj题 ——————————————————————— 题目介绍&#xff1a; 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通…

【C语言】操作符相关知识点

移位操作符 << 左移操作符 >>右移操作符 左移操作符 移位规则&#xff1a; 左边抛弃、右边补0 右移操作符 移位规则&#xff1a; 首先右移运算分两种&#xff1a; 1.逻辑移位 左边用0填充&#xff0c;右边丢弃 2.算术移位 左边用原该值的符号位填充&#xff0c;…

桥接模式以及在JDBC源码剖析

介绍&#xff1a; 1、桥接模式是指&#xff1a;将实现和抽象放在两个不同类层次中&#xff0c;使两个层次可以独立改变 2、是一种结构型设计模式 3、Bridge模式基于类的最小设计原则&#xff0c;通过使用封装、聚合以及继承等行为让不同的类承担不同的职责。 4、特点&#xff1…

【智能算法】樽海鞘群算法(SSA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.代码实现4.参考文献 1.背景 2017年&#xff0c;Mirjalili受到樽海鞘集群行为启发&#xff0c;提出了樽海鞘群算法(Salp Swarm Algorithm, SSA)。 2.算法原理 2.1算法思想 樽海鞘集群是领导者-追随者类型算法&#xff0c;整体…

基于SpringBoot的“医院信管系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“医院信管系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 功能结构图 系统首页界面图 用户注册界面图 医生…

CANopen转Profinet网关连接西门子PLC与变流器通讯

CANopen转Profinet网关&#xff08;XD-COPNm20&#xff09;在智能领域&#xff0c;变流器的应用非常广泛&#xff0c;变流器一般会采用CANopen协议。现场采用台达的变流器&#xff08;支持CANopen协议&#xff09;作为CANopen从站&#xff0c;S7-1500系列PLC做主站&#xff0c;…

软件设计不是CRUD(14):低耦合模块设计理论——行为抽象与设计模式(上)

是不是看到“设计模式”四个字,各位读者就觉得后续内容要开始讲一些假大空的内容了?各位读者是不是有这样的感受,就是单纯讲设计模式的内容,网络上能找到很多资料,但是看过这些资料后读者很难将设计模式运用到实际的工作中。甚至出现了一种声音:设计模式是没有用的,应用…

Python安装第三方库

前言&#xff1a;大部分时候我们都是使用pip install去安装一些第三方库&#xff0c;但是偶尔也会有部分库无法安装&#xff08;最典型的就是dlib这个库&#xff09;&#xff0c;需要采取别的方法解决&#xff0c;这里做笔记记录一下。 使用国内镜像源安装 因为pypi的服务器在…

Java后端八股文之Redis

文章目录 1. Redis是什么&#xff1f;2. Redis为什么这么快&#xff1f;3. 为什么要使用缓存&#xff1f;4. Redis几种使用场景&#xff1a;5. Redis的Zset底层为什么要使用跳表而不是平衡树、红黑树或者B树&#xff1f;6.Redis持久化6.1 什么是RDB持久化6.1.1RDB创建快照会阻塞…