算法设计优化——有序向量二分查找算法与Fibonacci查找算法

news2025/1/13 10:13:45

文章目录

  • 0.概述
  • 1.语义定义
  • 2. 二分查找(版本A)
    • 2.1 原理
    • 2.2 实现
    • 2.3 复杂度
    • 2.4 查找长度
  • 3.Fibonacci查找
    • 3.1 改进思路
    • 3.2 黄金分割
    • 3.3 实现
    • 3.4 复杂度分析
    • 3.5 平均查找长度
  • 4. 二分查找(版本B)
    • 4.1 改进思路
    • 4.2 实现
    • 4.3 性能
    • 4.4 进一步的要求
  • 5. 二分查找(版本C)
    • 5.1 实现
    • 5.2 正确性

0.概述

介绍有序向量二分查找算法的改进思路和原理、实现方式、复杂度分析。

1.语义定义

在有序向量区间V[lo,hi)中,约定search()接口返回不大于e的最后一个元素。

2. 二分查找(版本A)

2.1 原理

在这里插入图片描述
每经过至多两次比较操作,可以将查找问题简化为一个规模更小的新问题。如此,借助递归机制即可便捷地描述和实现此类算法。

2.2 实现

算法思想:减而治之

// 二分查找算法(版本A):在有序向量的区间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
template <typename T> 
static Rank binSearch ( T* A, T const& e, Rank lo, Rank hi ) {
	while ( lo < hi ) { //每步迭代可能要做两次比较判断,有三个分支
		Rank mi = ( lo + hi ) >> 1; //以中点为轴点
		if ( e < A[mi] ) hi = mi; //深入前半段[lo, mi)继续查找
		else if ( A[mi] < e ) lo = mi + 1; //深入后半段(mi, hi)继续查找
		else return mi; //在mi处命中
	} //成功查找可以提前终止
	return -1; //查找失败
} //有多个命中元素时,不能保证返回秩最大者;查找失败时,简单地迒回-1,而且能指示失败的位置
  • 通过快捷的整数移位操作回避了相对更加耗时的除法运算。
  • 通过引入lo、hi和mi等变量,将减治算法通常的递归模式改成了迭代模式。(递归消除)

2.3 复杂度

在这里插入图片描述
随着迭代的不断深入,有效的查找区间宽度将按1/2的比例以几何级数的速度递减。经过至多log2(hi - lo)步迭代后,算法必然终止。故总体时间复杂度不超过:
O( l o g 2 ( h i − l o ) log_2(hi - lo) log2(hilo)) = O(logn)
上图中的递归公式也可得出这个结论,递推公式不熟悉的可以看递推分析。

顺序查找算法的O(n)复杂度相比无序向量的查找find()无序向量,O(logn)几乎改进了一个线性因子(任意c > 0,logn = O( n c n^c nc))。

2.4 查找长度

查找算法的整体效率主要地取决于其中所执行的元素大小比较操作的次数,即所谓查找长度。

通常,需分别针对成功与失败查找,从最好、最坏、平均等角度评估

结论:版本A二分查找成功、失败时的平均查找长度均大致为O(1.5logn)

3.Fibonacci查找

3.1 改进思路

在这里插入图片描述
解决问题的思路:

  1. 其一,调整前、后区域的宽度,适当地加长(缩短)前(后)子向量 (此方法本次采用)
  2. 其二,统一沿两个方向深入所需要执行的比较次数,比如都统一为一次(此方法后面改进版本采用)

3.2 黄金分割

实际上,减治策略本身并不要求子向量切分点mi必须居中,故按上述改进思路,不妨按黄金分割比来确定mi。
在这里插入图片描述

3.3 实现

算法思路:减治策略——黄金分割比来确定mi

#include "..\fibonacci\Fib.h" //引入Fib数列类
// Fibonacci查找算法(版本A):在有序向量的区间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
template <typename T> static Rank fibSearch ( T* A, T const& e, Rank lo, Rank hi ) {
	Fib fib ( hi - lo ); //用O(log_phi(n = hi - lo)时间创建Fib数列
	while ( lo < hi ) { //每步迭代可能要做两次比较判断,有三个分支
		while ( hi - lo < fib.get() ) fib.prev(); //通过向前顺序查找(分摊O(1))——至多迭代几次?
		Rank mi = lo + fib.get() - 1; //确定形如Fib(k) - 1的轴点
		if ( e < A[mi] ) hi = mi; //深入前半段[lo, mi)继续查找
		else if ( A[mi] < e ) lo = mi + 1; //深入后半段(mi, hi)继续查找
		else  return mi; //在mi处命中
	} //成功查找可以提前终止
	return -1; //查找失败
} //有多个命中元素时,不能保证返回秩最大者;失败时,简单地迒回-1,而且能指示失败的位置

对Fib数不清楚得可以看算法设计优化——Fibonacci数

3.4 复杂度分析

进入循环之前调用构造器Fib(n = hi - lo),将初始长度设置为“不小于n的最小Fibonacci项”。这一步所需花费的O( l o g ϕ log_\phi logϕn)时间,分摊到后续O( l o g ϕ log_\phi logϕn)步迭代中,并不影响算法整体的渐进复杂度。

3.5 平均查找长度

结论:O(1.44∙log2n)

4. 二分查找(版本B)

4.1 改进思路

与二分查找算法的版本A基本类似。不同之处是,在每个切分点A[mi]处,仅做一次元素比较。
在这里插入图片描述

4.2 实现

// 二分查找算法(版本B):在有序向量癿匙间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
template <typename T> 
static Rank binSearch ( T* A, T const& e, Rank lo, Rank hi ) {
	while ( 1 < hi - lo ) { //每步迭代仅需做一次比较判断,有两个分支;成功查找不能提前终止
		Rank mi = ( lo + hi ) >> 1; //以中点为轴点
		( e < A[mi] ) ? hi = mi : lo = mi; //经比较后确定深入[lo, mi)或[mi, hi)
	} //出口时hi = lo + 1,查找匙间仅含一个元素A[lo]
	return ( e == A[lo] ) ? lo : -1 ; //查找成功时返回对应的秩;否则统一返回-1
} //有多个命中元素时,不能保证迒回秩最大者;查找失败时,简单地返回-1,而不能指示失败癿位置

4.3 性能

版本B中的后端子向量需要加入A[mi],但得益于mi总是位于中央位置,整个算法O(logn)的渐进复杂度不受任何影响。

在这一版本中,只有在向量有效区间宽度缩短至1个单元时算法才会终止,而不能如版本A那样,一旦命中就能及时返回。因此,最好情况下的效率有所倒退。当然,作为补偿,最坏情况下的效率相应地有所提高。实际上无论是成功查找或失败查找,版本B各分支的查找长度更加接近,故整体性能更趋稳定。

4.4 进一步的要求

在这里插入图片描述

  • 通过查找操作不仅能够确定可行的插入位置,而且能够在同时存在多个可行位置时保证返回其中的秩最大者。

  • 在查找失败时返回不大(小)于e的最后(前)一个元素,以便将e作为其后继(前驱)插入向量。

5. 二分查找(版本C)

5.1 实现

// 二分查找算法(版本C):在有序向量的区间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
template <typename T> 
static Rank binSearch ( T* A, T const& e, Rank lo, Rank hi ) {
	while ( lo < hi ) { //每步迭代仅需做一次比较判断,有两个分支
		Rank mi = ( lo + hi ) >> 1; //以中点为轴点
		( e < A[mi] ) ? hi = mi : lo = mi + 1; //经比较后确定深入[lo, mi)戒(mi, hi)
	} //成功查找不能提前终止
	return --lo; //循环结束时,lo为大于e的元素的最小秩,故lo - 1即不大于e的元素的最大秩
} //有多个命中元素时,总能保证返回秩最大者;查找失败时,能够返回失败的位置

5.2 正确性

版本C与版本B的差异,主要有三点。首先,只有当有效区间的宽度缩短至0(而不是1)时,查找方告终止。另外,在每次转入后端分支时,子向量的左边界取作mi + 1而不是mi。

版本C中的循环体,具有如下不变性:
A[0, lo)中的元素皆不大于e;A[hi, n)中的元素皆大于e

首次迭代时,lo = 0且hi = n,A[0, lo)和A[hi, n)均空,不变性自然成立。
如图所示,设在某次进入循环时以上不变性成立,以下无非两种情况。若e < A[mi],则如图(b),在令hi = mi并使A[hi, n)向左扩展之后,该区间内的元素皆不小于A[mi],当然也仍然大于e。反之,若A[mi] ≤ e,则如图©,在令lo = mi + 1并使A[0, lo)向右拓展之后,该区间内的元素皆不大于A[mi],当然也仍然不大于e。总之,上述不变性必然得以延续。
在这里插入图片描述
循环终止时,lo = hi。考查此时的元素A[lo - 1]和A[lo]:作为A[0, lo)内的最后一个元素,A[lo - 1]必不大于e;作为A[lo, n) = A[hi, n)内的第一个元素,A[lo]必大于e。也就是说,A[lo - 1]即是原向量中不大于e的最后一个元素。因此在循环结束之后,无论成功与否,只需返回lo - 1即可——这也是版本C与版本B的第三点差异。

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

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

相关文章

基于CANoe从零创建以太网诊断工程(2)—— TCP/IP Stack 配置的三种选项

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

手撕netty源码(二)- 初始化ServerBootstrap

文章目录 前言一、ServerBootstrap 的创建和初始化1.1 创建1.2 初始化group1.3 初始化channel1.3 初始化option和attr1.4 初始化handler 和 childHandler 总结 前言 processOn文档跳转 接上一篇&#xff1a;手撕netty源码&#xff08;一&#xff09;- NioEventLoopGroup 本篇讲…

uni-app app和h5的通信

uni-app一套代码同时打包安卓、iOS、h5,有一些需要app与h5的交互通信,目前做到了这块的业务,记录如下&#xff1a; 1.去declould官网,找到uni_webview.js下载链接,将uni_webview.js文件下载到本地&#xff0c;修改uni_webview.js内部配置,将uni修改为webUni,修改好的文件已放到…

SpringBoot中Bean的创建过程及扩展操作点 @by_TWJ

目录 1. 类含义2. Bean创建过程 - 流程图3. 例子3.1. 可变属性注入到实体中3.2. 模拟Bean创建的例子 1. 类含义 BeanDefinition - 类定义&#xff0c;为Bean创建提供一些定义类的信息。实现类如下&#xff1a; RootBeanDefinition - 类定义信息&#xff0c;包含有父子关系的Be…

智慧健康旅居养老产业,做智慧旅居养老服务的公司

随着社会的进步和科技的飞速发展&#xff0c;传统的养老模式已经无法满足 现代老年人的多元化 需求。智慧健康旅居养老产业应运而生&#xff0c;成为了一种新型的养老模式&#xff0c;旨在为老年人提供更加舒适、便捷、安全的养老生活。随着社会的进步和人口老龄化趋势的加剧&a…

五一劳动节活动策划案怎么写?

分享一个五一劳动节活动策划万能模板&#xff0c;直接照着写就好。 一、活动主题&#xff1a; 五一户外露营Party 二、活动时间&#xff1a; 五一节当天&#xff0c;上午点至下午点 三、活动地点&#xff1a; 城市郊外的公园或大型绿地 四、参与人员&#xff1a; 公司员…

自动化测试超详细总结

简介 软件测试是软件开发过程中一个必不可少的环节。传统的软件测试方式通常是手动测试&#xff0c;即由专业的测试人员通过手动操作软件应用程序来验证其功能和性能。然而&#xff0c;这种方式存在许多缺点&#xff0c;例如时间耗费、测试结果不稳定、测试覆盖率不够高等。 为…

Pandas 2.2 中文官方教程和指南(二十·二)

通过组进行迭代 有了 GroupBy 对象&#xff0c;通过分组数据进行迭代非常自然&#xff0c;类似于itertools.groupby()的操作&#xff1a; In [74]: grouped df.groupby(A)In [75]: for name, group in grouped:....: print(name)....: print(group)....: barA B…

AI智能写作工具,一键智能改写文章简单又高效

随着人们生活节奏的加快和工作压力的增大&#xff0c;如何在繁忙的日程中高效地写作成为了许多人的难题。但是随着人工智能技术的不断发展和应用&#xff0c;AI智能写作工具的出现&#xff0c;成为了许多人解决写作难题的利器。今天小编就来跟大家分享下AI智能写作工具&#xf…

go语言并发实战——日志收集系统(八) go语言操作etcd以及利用watch实现对键值的监控

有关包的安装 我们要实现go语言对第三方包的操作需要我们下载第三方包go.etcd.io&#xff0c;下载命令&#xff1a; go get go.etcd.io/etcd/client/v3 ectd的put与get操作 相关函数说明与示例 我们想实现对etcd进行简单的操作的步骤还是比较简单的&#xff0c;在我上一篇文…

Gateway基础知识

文章目录 Spring Cloud GateWay 用法核心概念请求流程两种配置方式设置日志&#xff08;建议设置&#xff09;路由的各种断言断言The After Route Predicate FactoryThe Before Route Predicate FactoryThe Between Route Predicate FactoryThe Cookie Route Predicate Factory…

海外盲盒APP开发:探索海外盲盒市场的商机

随着娱乐消费的流行&#xff0c;盲盒在我国可以说是非常火热&#xff0c;消费群体和市场规模逐年增加。在盲盒热潮下&#xff0c;不少潮玩企业也纷纷加入到了盲盒赛道中&#xff0c;市场竞争非常激烈&#xff01; 此外&#xff0c;我国盲盒出海也成为了一个大趋势。盲盒不仅在…

uni-app canvas 签名

调用方法 import Signature from "/components/signature.vue" const base64Img ref() //监听getSignImg uni.$on(getSignImg, ({ base64, path }) > {base64Img.value base64//console.log(签名base64, path >, base64, path) //拿到的图片数据// 之后取消…

Java程序员必须掌握的数据结构:HashMap

HashMap底层原理实现是每个Java Boy必须掌握的基本技能&#xff0c;HashMap也是业务开发每天都需要遇到的好伙伴。如此基础且核心的底层数据结构&#xff0c;JDK也给其赋予了线程安全的功能类&#xff0c;我们来看看~ &#x1f331;以【面试官面试】形式覆盖Java程序员所需掌握…

使用Kimi快速完成高质量学术论文全流程攻略!

点击下方▼▼▼▼链接直达AIPaperPass &#xff01; AIPaperPass - AI论文写作指导平台 目录 01.论文选题(重要指数:★★★★★) 02.摘要(重要指数:★★★★) 03.关键词(重要指数:★★★★) 04.引言(重要指数:★★★★) 05.正文(重要指数:★★★★★) 06.结论(重要指数…

能源监控可视化大屏的价值,不要说没啥用了,容易暴露格局

能源监控可视化大屏具有以下几个方面的价值&#xff1a; 实时监控&#xff1a; 能源监控可视化大屏可以实时展示能源系统的运行状态&#xff0c;包括电力、水、气等能源的消耗、供应情况&#xff0c;以及设备运行状态等。通过实时监控&#xff0c;可以及时发现异常情况和故障…

翻译《The Old New Thing》 - What does SHGFI_USEFILEATTRIBUTES mean?

What does SHGFI_USEFILEATTRIBUTES mean? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20040601-00/?p39073 Raymond Chen 2004年06月01日 在使用 SHGetFileInfo 函数时&#xff0c;你可以设置一个名为 SHGFI_USEFILEATTRIBUTES 的标志…

目标检测——3D玩具数据集

在数字化时代&#xff0c;计算机视觉技术取得了长足的进展&#xff0c;其中基于形状的3D物体识别技术更是引起了广泛关注。该技术不仅有助于提升计算机对现实世界物体的感知能力&#xff0c;还在多个领域展现出了广阔的应用前景。本文将探讨基于形状的3D物体识别实验的重要性意…

WMS之添加View

目录 前言一、addview示例二、addview流程2.1 流程图2.2 流程分析2.2.1 Actitity的启动流程创建PhoneWindow和DecorView2.2.2.WindowManagerImpl 添加view2.2.3 ViewRootImpl.setView 三、总结 前言 WMS 功能繁杂&#xff0c;通过添加View流程进一步分析WMS 通过本文了解掌握…

RPC分布式通信框架

在实际开发中单机服务器存在诸多问题&#xff1a; 1.受限于硬件资源无法提高并发量 2.任意模块的修改都将导致整个项目代码重新编译部署 3.在系统中&#xff0c;有些模块属于CPU密集型&#xff0c;有些属于I/O密集型&#xff0c;各模块对于硬件资源的需求不一样 什么是分布式&a…