C 语言二分查找法

news2024/12/23 16:40:28

二分查找定义


 二分查找法用于查找一个有序数组中某个目标值是否存在,或者接近目标值的元素;相比把
整个数组遍历一次的0(n)复杂度,二分查找可以把复杂度降低到0(logzn):


 原理讲解


原来中间的值mid = (left + right)/ 2,但是我们写成如下的形式:mid = left + (left + right) / 2
作用是防止在数据运算的过程中初出现数据溢出。这里我们的目标值是20就是一个升序的排序方式因此采用这种移动的方法,如果目标值不同则可能移动的是right指向的数组下标元素,根据求取目标值的不同使用不同的查找方式。

 


升序排序

注意:这三个的数据类型一定要是有符号的数据类型因为right的值可能是 -1 ,所以三个值需要时有符号整形变量,循环的结束条件是 left = right +1 也就是left向右边移动超过right的时候表示搜索的区间为空,循环结束。

这个代码对应的数数组的升序

 


 代码实现

#define _CRC_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>


/*
		二分查找升序的代码
*/
int32_t BinarySearch(int32_t *arr,int32_t size,int32_t key)
{
	int left = 0;
	int32_t right = size - 1;
	int32_t mid;
	while (left <= right) 
	{
		mid = left + (right - left) / 2;
		if (key < arr[mid]) 
		{
			right = mid - 1;
		}
		else if (key > arr[mid]) 
		{
			left = mid + 1;
		}
		else 
		{
			return mid;
		}
		
	}
	return -1;
}


int main() 
{
	int32_t arr[5] = { 5,8,1,3,9 };
	int len = sizeof(arr) / sizeof(arr[0]);
	int32_t index;
	index = BinarySearch(arr, len, 9);
	printf("9 index = %d.\n", index);
	index = BinarySearch(arr, len, 3);
	printf("3 index = %d.\n", index);
	index = BinarySearch(arr, len, 0);
	printf("0 index = %d.\n", index);
}

 结果:


降序排序

代码实现

#define _CRC_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>


/*
		二分查找升序的代码
*/
int32_t BinarySearch(int32_t *arr,int32_t size,int32_t key)
{
	int left = 0;
	int32_t right = size - 1;
	int32_t mid;
	while (left <= right) 
	{
		mid = left + (right - left) / 2;
		if (key < arr[mid]) 
		{
			right = mid - 1;
		}
		else if (key > arr[mid]) 
		{
			left = mid + 1;
		}
		else 
		{
			return mid;
		}
		
	}
	return -1;
}

/*
	二分查找降序
*/
int32_t DescBinarySearch(int32_t* arr, int32_t size, int32_t key) 
{
	int32_t left = 0;
	int32_t right = size - 1;
	int32_t mid;
	while (left <= right) 
	{
		mid = left + (right - left) / 2;
		if (key > arr[mid]) 
		{
			right = mid - 1;
		}
		else if (key < arr[mid]) 
		{
			left = mid + 1;
		}
		else 
		{
			return mid;
		}
	}
	return -1;
}

int main() 
{
	int32_t arr[5] = { 5,8,1,3,9 };
	int len = sizeof(arr) / sizeof(arr[0]);
	int32_t index;
#if 0
	index = BinarySearch(arr, len, 9);
	printf("9 index = %d.\n", index);
	index = BinarySearch(arr, len, 3);
	printf("3 index = %d.\n", index);
	index = BinarySearch(arr, len, 0);
	printf("0 index = %d.\n", index);
#endif
	int32_t arr2[6] = { 20,14,10,7,3,1 };
	index = DescBinarySearch(arr2, len, 20);
	printf("20 index = %d.\n", index);
	index = DescBinarySearch(arr2, len, 14);
	printf("14 index = %d.\n", index);
	index = DescBinarySearch(arr2, len, 0);
	printf("0 index = %d.\n", index);
}

结果:


使用场景:找到接近目标值的下标

升序查找接近值:

 思路解析:

使用二分查找法在有序数组中查找最接近目标值的元素,可以按照以下步骤进行:

给定数组 arr[] = {1, 3, 7, 10, 14, 20} 和目标值 target = 2

步骤 1: 初始化指针

  • low 指向数组的第一个元素,即 low = 0
  • high 指向数组的最后一个元素,即 high = 5(数组下标从0开始)。
  • mid 用于存储中间元素的下标。

步骤 2: 开始二分查找

进入循环,当 low <= high 时执行:

  1. 计算 mid:mid = low + (height  - low) / 2

  2. 注意:这里使用 (high - low) / 2 而不是 (low + high) / 2 避免了整数溢出的可能性

  3. 比较 arr[mid] 与 target:

    • 如果 arr[mid] == target,直接返回 arr[mid]。但在这个例子里,因为 target = 2 并不在数组中,我们不会遇到这种情况。
    • 如果 arr[mid] < target,更新 low = mid + 1
    • 如果 arr[mid] > target,更新 high = mid - 1

步骤 3: 计算最接近的元素

当退出循环时,lowhigh 之间的元素已经被排除在外。我们需要比较 arr[high]arr[low] 中哪一个更接近 target

  1. 比较最接近的元素:
    • 如果 low 已经超出数组范围,返回 arr[high]
    • 如果 high 已经低于0,返回 arr[low]
    • 否则,比较 arr[low]arr[high] 哪个离 target 更近。

让我们根据上述步骤具体计算一下:

  1. 初始时,low = 0, high = 5
  2. 第一次循环,mid = (0 + 5) / 2 = 2,检查 arr[2] = 7,因为 7 > target,所以 high = mid - 1 = 1
  3. 第二次循环,mid = (0 + 1) / 2 = 0,检查 arr[0] = 1,因为 1 < target,所以 low = mid + 1 = 1
  4. 第三次循环,low = 1high = 1mid = 1,检查 arr[1] = 3,因为 3 > target,但是 lowhigh 相等,所以退出循环。

此时,lowhigh 都等于 1,arr[1] = 3。由于 low 不会超出数组范围,我们只需要检查 arr[1] 是否是最接近的。因为 target = 2,显然 arr[1] = 3 是最接近 target 的元素。

结论:

最接近目标值 2 的元素是 3


代码实现

#define _CRC_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int32_t AsecNear(int32_t* arr, int32_t size, int32_t key)
{
	int32_t left = 0;
	int32_t right = size - 1;
	int32_t mid;
	int32_t index = size - 1;
	while (left <= right)
	{
		mid = left + (right - left) / 2;
		if (key <= arr[mid])
		{
			right = mid - 1;
			index = mid;
		}
		else
		{
			left = mid + 1;
		}
	}
	return index;
}


int main() 
{
		int32_t arr[6] = { 1, 3, 7, 10, 14, 20 };
		int32_t index;
	//	index = AsecBinarySearch(arr, 6, 20);
		index = AsecNear(arr, 6, 20);
		printf("20 index = %d.\n", index);
		index = AsecNear(arr, 6, 11);
		printf("14 index = %d.\n", index);
		index = AsecNear(arr, 6, 21);
		printf("0 index = %d.\n", index);
		index = AsecNear(arr, 6, 0);
		printf("0 index = %d.\n", index);
		int32_t arr2[6] = { 20, 14, 10, 7, 3, 1 };
}

结果:


降序查找目标值

代码实现

#define _CRC_SECURE_NO_WARNINGS
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int32_t DescNear(int32_t* arr, int32_t size, int32_t key)
{
	int32_t left = 0;
	int32_t right = size - 1;
	int32_t mid;
	int32_t index = size - 1;
	while (left <= right)
	{
		mid = left + (right - left) / 2;
		if (key >= arr[mid])
		{
			right = mid - 1;
			index = mid;
		}
		else
		{
			left = mid + 1;
		}
	}
	return index;
}

int main() 
{
	int32_t arr[6] = { 1, 3, 7, 10, 14, 20 };
	int32_t index;
	int32_t arr2[6] = { 20, 14, 10, 7, 3, 1 };
	index = DescNear(arr2, 6, 20);
	printf("20 index = %d.\n", index);
	index = DescNear(arr2, 6, 11);
	printf("11 index = %d.\n", index);
	index = DescNear(arr2, 6, 21);
	printf("21 index = %d.\n", index);
	index = DescNear(arr2, 6, 0);
	printf("0 index = %d.\n", index);
}

结果:

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

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

相关文章

用NSAT-1000实现S参数的自动化测试

在射频技术领域&#xff0c;S参数的准确测量对于保证产品质量至关重要。本文将带您了解NSAT-1000测试系统实现S参数自动化测试的流程。 S参数的测试原理 S参数测试原理是基于网络分析仪&#xff0c;网络分析仪发出一个已知频率和幅度的射频信号&#xff0c;通过网分测量信号得到…

eclipse Web Browser Setting

eclipse Web Browser Setting 默认程序打开浏览器的设置 Windows - Preference - General - Web Browser 没有设置的时候&#xff0c;就是你自己要手动打开浏览器&#xff0c;地址栏敲进去&#xff0c;例如&#xff1a; http://127.0.0.1:7070/FRTIMP_YTFRB_WEB/bin/MainApp.…

PHP高校迎新系统-计算机毕业设计源码08468

摘要 随着高校规模的不断扩大和新生人数的增加&#xff0c;传统的手工登记和管理方式已经无法满足高效、准确的需求。为了提升大学新生入学迎新工作的效率和质量&#xff0c;本研究设计开发了一套高校迎新系统。系统通过信息技术的应用&#xff0c;集成了首页、交流论坛、通知公…

万顺汽车租赁推荐系统

1 项目介绍 1.1 摘要 随着汽车租赁市场的不断发展&#xff0c;为了提升用户体验和管理效率&#xff0c;开发了一套集管理员和用户功能于一体的汽车租赁平台系统。该系统旨在提供便捷的用户信息管理、车辆信息管理、租赁订单管理等功能&#xff0c;以满足管理员和用户的不同需…

DTU、RTU和边缘计算网关的联系与区别

在工业4.0发展浪潮中&#xff0c;物联网助力工业逐渐向智能化发展&#xff0c;各种工业设备相互连接起来形成物联网。而传输层作为物联网体系中十分重要的一环&#xff0c;它是连接物理世界与数字世界的桥梁&#xff0c;是数据的第一入口。 其中&#xff0c;我们经常会使用到三…

探索Python为何成爬虫开发首选

大家在日常生活中会不会有这样的疑惑——为什么在进行网络爬虫开发时&#xff0c;大多数开发者更倾向于选择Python而不是Java。Python在爬虫领域的受欢迎程度背后有多个原因&#xff0c;让我们一起来了解一下。 一、简洁易学的语法 Python以其简洁易学的语法著称&#xff0c;使…

包装类与泛型

泛型与包装类密切相关&#xff0c;在学习泛型前先了解了解包装类吧 包装类 包装类是对应着各种基本数据类型进行包装后产生的引用数据类型 ,是基本数据类型的plus版本。 为什么要设计包装类 因为 Java是一个面向对象的编程语言&#xff0c;但是Java中的八种基本数据类型却是…

科普文:微服务之Spring Cloud Alibaba组件熔断过载保护器Sentinel

一、什么是Sentinel Sentinel是阿里开源的项目&#xff0c;提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。 官网&#xff1a;Home alibaba/Sentinel Wiki GitHub 2012年&#xff0c;Sentinel诞生于阿里巴巴&#xff0c;其主要目标是流量控制。…

浅谈几个常用OJ的注册方式

众所周知&#xff0c;好的OJ是成功的一半&#xff0c;但是有些英文OJ的注册很让人伤脑筋。 CodeForces 点进官网 戳这里 然后就会进入这个页面 在这一页里面里填写好信息即可 最后&#xff0c;一个邮件就会发到你的邮箱上&#xff0c;点击其中的链接即可激活账号 AtCoder …

软件测试生命周期、BUG描述与处理策略指南

软件测试的生命周期 需求分析&#xff1a;需求是否完整、是否正确 测试计划&#xff1a;确定由谁测试、测试的起止时间、设计哪些模块 测试设计、测试开发&#xff1a;写测试用例&#xff08;手工、自动化测试用例&#xff09;、编写测试工具 执行测试用例 测试评估&…

从文本到图像:深度解析向量嵌入在机器学习中的应用

简介 向量嵌入是机器学习领域中一项极具吸引力且实用的技术&#xff0c;它为多种应用提供了基础支撑&#xff0c;包括自然语言处理&#xff08;NLP&#xff09;、推荐系统和搜索算法。无论是推荐引擎、语音助手还是语言翻译器&#xff0c;这些系统的背后都可能运用了向量嵌入技…

ventoy和微pe可以共存吗?ventoy和pe共存使用教程

Ventoy新一代多系统启动U盘解决方案。国产开源U盘启动制作工具&#xff0c;支持Legacy BIOS和UEFI模式&#xff0c;理论上几乎支持任何ISO镜像文件&#xff0c;支持加载多个不同类型的ISO文件启动&#xff0c;无需反复地格式化U盘&#xff0c;插入U盘安装写入就能制作成可引导的…

将网络变压器(Ethernet Transformer)从千兆单口设计改为百兆双口设计涉及几个关键步骤和注意事项

变压器选型&#xff1a; 确保选用的变压器支持1000BASE-T到100BASE-TX的转换。通常&#xff0c;这种变压器会有额外的电气特性&#xff0c;如抑制和隔离等&#xff0c;以确保数据传输的可靠性和稳定性。 端口连接&#xff1a; 对于千兆单口设计&#xff0c;通常会有一对输入和输…

maya动画时间轴在哪里调出来?

在Maya动画制作中&#xff0c;时间轴是控制动画节奏和时间的关键工具。但初学者常困惑于时间轴的隐藏问题。本文将指导你如何找回并利用Maya的时间轴&#xff0c;确保你的动画制作流程顺畅无阻。 maya动画时间轴调出来方法 1、登录 Maya 软件&#xff0c;在显示设置中调出时间…

Day16_2--Servlet学习之过滤器+session实现防跳墙

Servlet过滤器Fileter是一个小型的web组件&#xff0c;它们通过拦截请求和响应&#xff0c;以便查看、提取或以某种方式操作客户端和服务器之间交换的数据&#xff0c;实现“过滤”的功能。Filter通常封装了一些功能的web组件&#xff0c;过滤器提供了一种面向对象的模块化机制…

使用生成式对抗网络(GAN)生成动漫人物图像

【图书推荐】《PyTorch深度学习与企业级项目实战》-CSDN博客 《PyTorch深度学习与企业级项目实战&#xff08;人工智能技术丛书&#xff09;》(宋立桓&#xff0c;宋立林)【摘要 书评 试读】- 京东图书 (jd.com) 如今AI艺术创作能力越来越强大&#xff0c;Google发布的ImageGe…

算法板子:BFS(广度优先搜索)——迷宫问题,求从迷宫的起点到终点的最短路径; 八数码问题,求从初始布局到最终布局x最少移动多少次

目录 1. 核心思想在于bfs函数2. 代码中用到的数组的含义解释3. 迷宫问题&#xff08;1&#xff09;求从(0,0)点到(4,4)点的最短路径是多少——bfs函数&#xff08;2&#xff09;打印最短路径——在bfs函数的基础上多了一个print函数a. 思想b. 代码 4. 八数码问题——bfs函数 1.…

科普文:微服务之Spring Cloud Alibaba消息队列组件RocketMQ工作原理

概叙 本文探讨 RocketMQ 的事务消息原理&#xff0c;并从源码角度进行分析&#xff0c;以及事务消息适合什么场景&#xff0c;使用事务消息需要注意哪些事项。 同时详细介绍RocketMQ 事务消息的基本流程&#xff0c;并通过源码分析揭示了其内部实现原理&#xff0c;尽管事务消…

【avue+vue2+elementui】删除、rules、页面跳转、列表数据过长、日期dayjs

这里写目录标题 一、删除二、rules三、页面跳转四、列表数据过长截断五、日期 dayjs一、删除 🍃API/*** 删除.* @param {*} data * @returns 返参*/ export const deleteOrder = (data) => {return request({url: /api/Order/deleteOrder,method: post,data}) }HTML🍃左…

常见病症之中医药草一枝黄花

常见病症之中医药草一枝黄花 1. 源由2. 一枝黄花植物描述药用部分主要成分药理作用使用方法注意事项 3. 常用方剂3.1 一枝黄花汤3.2 一枝黄花解毒汤 4. 着凉感冒主要方剂加味处方使用方法注意事项 5. 补充资料 1. 源由 注&#xff1a;仅供参考&#xff0c;建议在中医师指导下使…