二分查找及其扩展

news2024/9/29 23:30:34

目录

二分查找算法思想:

循环

递归

有多个与key相等数据的查询,找最左边与关键字相等的那个

找第一个大于key的元素的下标

有序循环数组的二分查找


二分查找算法思想:

二分查找也叫折半查找,查找效率较高。但是查找的线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

       线性表元素升序排列,将线性表中间位置的关键字与查找关键字比较,如果两者相等,则查找成功,否则将线性表一分为二。分治策略

如果中间位置的值大于查找关键字,则在左子表继续查找,否则查找右子表。

重复以上过程直到查找成功,返回位置信息。若子表为空了仍未找到返回-1,查找失败。

二分查找的时间复杂度是O(log(n)),最坏情况下的时间复杂度是O(n)。


循环

int binary_search(const int* nums, int n, int key)
{
	int left = 0;
	int right = n - 1;
	int mid = 0;
	int pos = -1;
	while (left <= right)//left和right是数据的规模,==时还有一个数据在里面,所以必须有=而非left<right
	{
		mid = (left + right) / 2;
		//也可以写成  mid = (right-left)/2+left,+left因为他是一个绝对规模,不能相对相减
		if (nums[mid] > key)
			right = mid - 1;
		else if (nums[mid] < key)
			left = mid + 1;
		else
		{
			pos = mid;
			break;
		}
	}
	return pos;
}

递归

        分治策略处理一个区域时,不能只用一个参数控制

int Find(const int* nums, int left, int right, int key)
{
	if (left <= right)
	{
		int mid = left + ((right - left) >> 1);
		if (nums[mid] > key)
			return Find(nums, left, mid - 1, key);
		else if (nums[mid] < key)
			return Find(nums, mid + 1, right, key);
		else
			return mid;
	}
	return -1;
}
int binarySearch(int* nums, int n, int key)
{
	assert(n > 0);
	int left = 0;
	int right = n - 1;
	return Find(nums, left, right, key);
}

有多个与key相等数据的查询,找最左边与关键字相等的那个

算法思想:先用二分查找找到一个与key相同的元素,然后顺序查看其左边的元素是否也与key相同,直到找到最左边的(数组查完/左边元素不等于key)。

算法改进:找到与key相同的元素后查看其左边第一个(不越界的情况下)是否也相同,如果不相同则没有多个,直接返回。如果相同则继续用二分查找找左边子序列与key相同的。

这样是为了避免有如:在序列3 3 3 3 3 3 3 3中查找3,完全没有了二分的优势。

int binary_search(const int* nums, int n, int key)
{
	int left = 0;
	int right = n - 1;
	int mid = 0;
	int pos = -1;
	while (left <= right)
	{
		mid = left + (left + right >> 1);
		if (nums[mid] > key)
			right = mid - 1;
		else if (nums[mid] < key)
			left = mid + 1;
		//else//二分查询到之后线性查询,一个挨着一个找
		//{
		//	while (mid>left && nums[mid-1] == key )//这个调节不能写反,否则越界
		//	{
		//		--mid;
		//	}
		//	pos = mid;
		//	break;
		//}
		//改进
		else
		{
			if (mid == left || nums[mid - 1] != key) return mid;//已经是最左边了
			else
			{
				right = mid - 1;
				continue;
			}
		}
	}
	return pos;
}

找第一个大于key的元素的下标

                mid<key,则不用在left-mid区间进行查找。

                mid==key时,如果下一个元素不等于key,则下一个为所找元素;

                                        如果下一个也等于key,则在右子序列继续二分查找。

                mid>key,则与上一题同理。

找第一个小于反之。

int binary_search(const int* nums, int n, int key)
{
	int left = 0;
	int right = n - 1;
	int mid = 0;
	int pos = -1;
	while (left <= right)
	{
		mid = left + (right-left >> 1);
		if (nums[mid] >= key)
		{
			if (nums[mid] == key)
			{
				if (nums[mid + 1] == key)
					left = mid + 1;
				else
					return mid + 1;
			}
			else 
			{
				if (nums[mid - 1] > key)
				{
					right = mid - 1;
				}
				else
					return mid;
			}
		}
		else if (nums[mid] < key)
			left = mid + 1;
	}
	return pos;
}
int main()
{
	int arr[10] = {0,1,2,3,4,5,6,6,8,9};
	printf("%d ", binary_search(arr, 10, 5));
	return 0;
}

有序循环数组的二分查找


有序循环数组如:4,5,6,7,8,9,10,1,2,3;查询给定的key是否在顺序表中,在哪。
先找到循环的点,再二分查找。

        在一个有序子串中取一值,left一定比它小;在另一子串中取值,left一定比它大。这样产生mid指向任意值,就可以判断循环的断点在mid的左边还是右边了。

 

int binary_search(const int* nums, int n, int key)
{
	int left = 0;
	int right = n - 1;
	int mid=0,bmid=0;
	int pos = -1;
	while (left < right)
	{
		bmid = left + (right - left >> 1);
		if (nums[bmid] == key)
			return bmid;
		else if (nums[left] < nums[bmid])//循环点在bmid右边
		{
			left = bmid;
		}
		else if (nums[left] > nums[bmid])//在bmid左边
		{
			right = bmid;
		}
		else
		{
			bmid++;
			break;
		}
	}
	printf("bmid==%d\n",bmid);
	//找到循环点了
	if (nums[0] <= key)//key应该在左边
	{
		left = 0;
		right = bmid - 1;
	}
	else
	{	
		left = bmid;
		right = n - 1;
	}
	while (left <= right)
	{
		mid = left+(right-left>>1);
		if (nums[mid] > key)
			right = mid - 1;
		else if (nums[mid] < key)
			left = mid + 1;
		else
		{
			pos = mid;
			break;
		}
	}
	return pos;
}
int main()
{
	int arr[10] = { 4,5,6,7,8,9,10,1,2,3};
	printf("%d \n", binary_search(arr, 10, 5));
	return 0;
}

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

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

相关文章

振弦采集模块电子标签测量(智能振弦传感器)

振弦采集模块电子标签测量&#xff08;智能振弦传感器&#xff09; 此功能在 SF3.52 版本时增加。 固件版本 V3.52 修改固件版本号为 V3.52_2201009。 增加了电子标签测量功能。 WKMOD.[12]用于控制是否使用此功能 新增状态位 STATUS.[13]&#xff0c;用来表示是否检测到了电子…

JAVA开发运维(DevOps过程)

DevOps开发运维的一套方法论。这边文章主要借鉴万达的DevOps的建设过程。谈谈DevOps主要解决那些问题和怎么解决。DevOps的是一种IT项目开发管理方法论&#xff0c;它旨在提供全面的持续集成、持续交付等能力&#xff0c;并持在续进行过程度量和改进&#xff0c;不断提升 IT 运…

新电脑安装vmware和centos8系统

1.安装vmware 1.1.vmware官网下载 需要付费 1.2.使用指定破解版本 链接&#xff1a;https://pan.baidu.com/s/1YEeaDyKAQk_3t6ITw2aaTQ 提取码&#xff1a;fjyf vmware16最新许可证密钥&#xff1a; ZF3R0-FHED2-M80TY-8QYGC-NPKYF YF390-0HF8P-M81RQ-2DXQE-M2UT6 ZF71R-DMX…

HTML实现网站欢迎页过渡

演示 一秒后直达主界面 css html, body {background: radial-gradient(#181818, #000000);margin: 0;padding: 0;border: 0;-ms-overflow-style: none;}::-webkit-scrollbar {width: 0.5em;height: 0.5em;background-color: #c7c7c7;}/*定义滚动条轨道 内阴影圆角*/::-webkit…

c++11 标准模板(STL)(std::forward_list)(二)

定义于头文件 <forward_list> template< class T, class Allocator std::allocator<T> > class forward_list;(1)(C11 起)namespace pmr { template <class T> using forward_list std::forward_list<T, std::pmr::polymorphic_…

什么是数字孪生城市

数字孪生城市理念自提出以来不断升温&#xff0c;已成为新型智慧城市建设的热点&#xff0c;受到政府和产业 界的高度关注和认同。 什么是数字孪生城市 北京智汇云舟科技有限公司成立于2012年&#xff0c;专注于创新性的“视频孪生&#xff08;实时实景数字孪生&#xff09;”…

【Java编程进阶】Java抽象类与接口详解

推荐学习专栏&#xff1a;Java 编程进阶之路【从入门到精通】&#xff0c;从入门到就业精通&#xff0c;买不了吃亏&#xff0c;买不了上当&#xff01;&#xff01; 文章目录1. 抽象类2.接口3. 抽象类和接口对比4. 总结Java基础教程系列文章1. 抽象类 前面说到&#xff0c;Ja…

【营销获客三】信贷细分客群研究——小微企业主

【营销获客三】信贷细分客群研究——小微企业主一、小微企业主客群综述1.1 小微企业主定义与体量1.2 小微企业主信贷需求规模1.3 小微企业主的发展历史1.4 小微企业主不同阶段的痛点问题二、小微企业主整体客群特征2.1 客群特征概述2.2 基本属性特征2.3 经营情况特征2.4 融资借…

RTL8380M/RTL8382M管理型交换机系统软件操作指南五:ACL/访问控制列表

接下来将对ACL进行详细的描述&#xff0c;主要包括以下四个方面内容&#xff1a;ACL概述、工作原理、ACL组设置、ACL规则 1.1 ACL概述 访问控制列表&#xff08;Access Control List&#xff0c;ACL&#xff09; 是路由器和交换机接口的指令列表&#xff0c;用来控制端口进出的…

自连接讲解

什么是自连接&#xff1f; 自连接可以理解为自己连接自己&#xff0c;在一张表上面所进行的操作&#xff1b;将一张表分成两张结构和数据完全一样的表&#xff0c;相当于克隆了一张跟自己长得一模一样的表&#xff1b; 但是既然是两张一模一样的表&#xff0c;数据库怎么去区分…

[ 数据结构 ] 汉诺塔--------分治算法最佳实践

0 分治算法 分治法:是一种很重要的算法。字面上的解释是“分而治之”&#xff0c;就是把一个复杂的问题分成两个或更多的相同或相似的子问题&#xff0c;再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解&#xff0c;原问题的解即子问题的解的合并。经典问题:…

什么你还不知道?快来看看我的年度总结吧

作者介绍&#xff1a;阿玥的小东东 作者职位&#xff1a;后端、python、正在学习c 主页&#xff1a;阿玥的小东东 现在呢&#xff0c;人们都在写自己的年度总结&#xff0c;我也来凑个热闹吧&#xff01; 其实我来CSDN这个平台时间不算久&#xff0c;从2022年11月15号开始&…

<C++>set和map

文章目录1. 关联式容器2. 键值对3. 树形结构的关联式容器4. set4.1 set的介绍4.2 set的使用4.2.1 set的模板参数4.2.2 set的构造4.2.3 set的迭代器4.2.4 set的容量4.2.5 set修改操作4.2.6 set的使用举例5. multiset5.1 multiset的介绍5.2 multiset的使用6. map6.1 map的介绍6.2…

字符串相关类

文章目录一、String类String的介绍String实例化面试题&#xff1a;String snew String("abc")创建对象&#xff0c;在内存中创建了几个对象&#xff1f;易错题1易错题2String常用方法String与char[ ]之间的转换String与byte[ ]之间的转换二、StringBuffer类、StringB…

如何将NACOS作为配置中心

新建一个命名空间 点击创建配置 关键点1&#xff1a;Data ID的命名规则&#xff1a; 前面我们演示了在 nacos 控制台新建一个 DataID 为 cloud-producer-server-dev.yaml 的数据集&#xff0c;那么这个 Data ID 是什么呢&#xff1f;Data ID 是配置集的唯一标识&#xff0c;一个…

CSS初级教程(字体)【第七天】

文章目录【1】CSS 字体【2】CSS 字体样式【3】CSS 字体大小【4】CSS 谷歌字体【5】CSS 字体属性【6】所有 CSS 字体属性CSS上回学习链接 CSS初级教程 颜色【第一天】 CSS初级教程 背景【第二天】 CSS初级教程 边框【第三天】 CSS初级教程 边距、高度、宽度【第四天】 CSS初级教…

ChatGPT的注册和使用教程

1 简介在时下热门话题AI作画之外&#xff0c;最近一个名叫ChatGPT的聊天机器人又掀起了一股人工智能的热潮。已有无数人投入到对它的测试研究之中&#xff0c;想探清它到底无所不能到何种地步。据悉&#xff0c;已有超过百万人与机器人聊天&#xff0c;甚至导致网站一度崩溃。那…

URDF与RVIZ

#来自赵虚左的资料&#xff0c;视频 创建功能包urdf01_rviz&#xff0c;依赖rviz xacro(比较简单使用) <launch> <!-- 设置参数 --> <param name"robot_description" textfile"$(find urdf01_rviz)/urdf/urdf/demo01_helloworld.urdf"…

Docker软件安装文档

软件安装文档 文章目录软件安装文档虚拟机安装系统死锁问题JDK11安装Docker安装Docker-Compose安装MySQL安装MySQL8安装Docker-Compose安装MySQL8MySQL5.7安装Nacos安装Docker安装Nacos单机Docker-Compose安装Nacos集群OpenResty安装Redis安装Docker安装单机RedisDocker-Compos…

【Unity3D】点选物体、框选物体、绘制外边框

1 需求描述 点选物体&#xff1a;点击物体&#xff0c;可以选中物体&#xff0c;按住 Ctrl 追加选中&#xff0c;选中的物体设置为红色。框选物体&#xff1a;拖拽鼠标&#xff0c;屏幕上会出现滑动框&#xff0c;滑动框内的物体会被选中&#xff0c;选中的物体设置为红色。绘…