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

文章目录

  • 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.mzph.cn/diannao/3263.shtml

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

相关文章

YOLOv8常见水果识别检测系统(yolov8模型,从图像、视频和摄像头三种路径识别检测)

1.效果视频&#xff08;常见水果识别&#xff08;yolov8模型&#xff0c;从图像、视频和摄像头三种路径识别检测&#xff09;_哔哩哔哩_bilibili&#xff09; 资源包含可视化的水果识别检测系统&#xff0c;可识别图片和视频当中出现的六类常见的水果&#xff0c;包括&#xf…

【redis】非关系型数据库——Redis介绍与安装(windows环境)

目录 数据库架构的演化单体架构缓存(Memcached)MySQL集群缓存(Memcached可以)MySQL集群垂直拆分&#xff08;主从复制&#xff0c;读写分离&#xff09;缓存(Redis)MySQL集群垂直拆分分库分表 NoSQLNoSQL产生的背景性能需求MySQL的扩展性瓶颈方面什么是NoSQLNoSQL的特点主流的N…

下级平台级联EasyCVR视频汇聚安防监控平台后,设备显示层级并存在重复的原因排查和解决

视频汇聚平台/视频监控系统/国标GB28181协议EasyCVR安防平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、云存储等丰富的视频能力&#xff0c;平台支持7*24小时实时高清视频监控&#xff0c;能同时…

C语言进阶|单链表的实现

✈链表的概念和结构 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表 中的指针链接次序实现的。 链表的结构跟火车车厢相似&#xff0c;淡季时车次的车厢会相应减少&#xff0c;旺季时车次的车厢会额外增加几节。…

BSV区块链协会上线首个版本的ARC交易处理器

​​发表时间&#xff1a;2024年3月28日 BSV区块链协会近期上线了首个版本的ARC交易处理器。ARC是一项区块链交易处理服务&#xff0c;能在通过P2P网络广播交易之前验证并存储相关的交易。一旦新区块被挖出&#xff0c;一条与该交易相关的Merkle路径将被发回给交易发起者作为确…

长效静态代理IP如何改变你的SEO和网络营销策略?

长效静态代理IP为SEO和网络营销专家提供了一个强大的工具&#xff0c;通过这种技术&#xff0c;可以突破传统的限制&#xff0c;以全新的视角和方法优化其在线策略。这不仅增强了企业的市场竞争力&#xff0c;也为实现更高效、更精准的营销目标提供了可能。 一、长效静态代理IP…

Vue面试经验

Vue编译时声明周期的执行顺序 Vue中父子组件渲染顺序&#xff08;同步引入子组件&#xff1a;import Son from ‘/components/son’ &#xff09; 父子组件编译时的生命周期执行顺序 这里修改data数据时也修改了dom&#xff0c;如过知识通过按钮对数据进行操作&#xff0c;那…

kafka大数据采集技术实验(未完待续)

Kafka环境搭建 下载地址&#xff1a;https://link.zhihu.com/?targethttps%3A//kafka.apache.org/downloads解压启动zookeeper bin/zookeeper-server-start.sh config/zookeeper.properties需要注意的是 : " c o n f i g / z o o k e e p e r . p r o p e r t i e s &q…

解密Java线程池源码

一、线程池中的保活和回收源码分析 1、线程池中线程的创建时机 1、核心线程创建时机 在研究线程池的源码前首先想一个问题 public class Main {public static void main(String[] args) {ThreadPoolExecutor executor new ThreadPoolExecutor(10, 20, 0l, TimeUnit.MILLIS…

从Linux角度具体理解程序翻译过程-----预处理、编译、汇编、链接

目录 前言&#xff1a; 翻译过程 1.预处理 2.编译 3.汇编 4.链接 Linux下对其理解&#xff1a; 1.预处理 拓展&#xff1a; Linux下文件信息&#xff1a; 文件类型&#xff1a; 硬链接数&#xff1a; 文件拥有者&#xff1a; 文件所属组&#xff1a; other&#x…

区块链安全应用-------压力测试

基于已有的链进行测试&#xff08;build_chain默认建的链 四个节 点&#xff09;&#xff1a; 第一步&#xff1a;搭链 1. 安装依赖 在ubuntu操作系统中&#xff0c;操作步骤如下&#xff1a; sudo apt install -y openssl curl 2. 创建操作目录, 下载安装脚本 ## 创建操作…

3个比较不错的Linux云音乐应用程序整理

在现代音乐流媒体时代&#xff0c;基于云的音乐应用程序因其便利性和可访问性而变得非常流行。Linux 用户尤其寻求可靠且功能丰富的音乐播放器来无缝地享受他们喜爱的音乐。 在这里&#xff0c;我们探讨了三个最好的基于云的音乐应用程序&#xff0c;每个应用程序都提供专为 L…

Java Web 网页设计(1)

不要让追求之舟停泊在幻想的港湾 而应扬起奋斗的风帆 驶向现实生活的大海 网页设计 1.首先 添加框架支持 找到目录右键添加 找到Web Application选中 点击OK 然后 编辑设置 找到Tomcat--local 选中 点击OK 名称可以自己设置 找到对应文件夹路径 把Tomcat添加到项目里面 因为…

【Hadoop】-HDFS的Shell操作[3]

目录 前言 一、HDFS集群启停命令 1.一键启停脚本可用 2.独立进程启停可用 二、文件系统操作命令 1、创建文件夹 2、查看指定目录下内容 3、上传文件到HDFS指定目录下 4、查看HDFS文件内容 5、下载HDFS文件 6、拷贝HDFS文件 7、追加数据到HDFS文件中 8、HDFS数据移…

哪吒汽车把最后的翻身筹码,全压在了这辆新车上

正如比亚迪王传福所说&#xff0c;新能源车市场已进入惨烈淘汰赛环节。 近几年国内新能源车销量增长势头迅猛&#xff0c;仅过去的 2023 年产销便分别达 958.7 万辆和 949.5 万辆&#xff0c;同比增长 35.8% 和 37.9%。 销量高速增长背后自然也带来了越来越激烈的竞争。 过去…

Footprint Analytics 与 GalaChain 达成战略合作

​ Footprint Analytics 宣布与 GalaChain 达成战略合作。GalaChain 是 Gala 旗下的 Layer 1 区块链。此次合作标志着双方在游戏&#xff08;包括 Gala Games) 、娱乐和金融等多个行业的区块链生态系统革新方面迈出了重要的一步。 GalaChain 致力于满足企业级项目的广泛需求&…

算法-栈操作

1047. 删除字符串中的所有相邻重复项 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:string removeDuplicates(string s) {string stack;for(char& ch:s){if(stack.size()>0&&chstack.back()){stack.pop_back();}else{stack.push_back(ch);}…

AI大模型实现软件智能化落地实践

1、什么是大模型 大型语言模型&#xff08;Large Language Model&#xff0c;LLM&#xff1b;Large Language Models&#xff0c;LLMs)。 大语言模型是一种深度学习模型&#xff0c;特别是属于自然语言处理&#xff08;NLP&#xff09;的领域&#xff0c;一般是指包含数干亿&…

Pandas 模块-操纵数据(11)-二元运算--超级add、sub、mul、div、mod、pow等等

目录 1. DataFrame.add 1.1 DataFrame.add 语法结构 1.2 DataFrame.add 参数说明 1.3 DataFrame.add 用法示例 1.3.1 正常的使用 1.3.2 需要注意类型相符合 2. DataFrame.sub 2.1 DataFrame.sub 语法结构 2.2 DataFrame.sub 参数说明 2.3 DataFrame.sub 用法示例 3.…

传媒论坛编辑部传媒论坛杂志社传媒论坛杂志2024年第7期目录

专题│场景传播研究 场景传播&#xff1a;一场遮盖自我与寻找自我的博弈 胡沈明; 3 基于CiteSpace的中国场景传播研究热点分析 管倩;粟银慧; 4-610《传媒论坛》投稿&#xff1a;cnqikantg126.com 数字世界的美与危&#xff1a;场景传播的失范与应对之举 王依晗;章洁…