【数据结构(邓俊辉)学习笔记】向量04——有序向量

文章目录

  • 0.概述
  • 1.比较器
  • 2.有序性甄别
  • 3.唯一化
    • 3.1低效算法
    • 3.1.1实现
    • 3.1.2 复杂度
    • 3.1.3 改进思路
    • 3.2 高效算法
      • 3.2.1 实现
      • 3.2.2 复杂度
  • 4.查找
    • 4.1统一接口
    • 4.2 语义定义
    • 4.3 二分查找
      • 4.3.1 原理
      • 4.3.2 实现
      • 4.3.3 复杂度
      • 4.3.4 查找长度
      • 4.3.5 不足
    • 4.4 Fibonacci查找
      • 4.4.1 思路及原理
      • 4.4.2 实现

0.概述

若向量S[0, n)中的所有元素不仅按线性次序存放,而且其数值大小也按此次序单调分布,则称作有序向量(sorted vector)。

1.比较器

有序向量的定义的先决条件:各元素之间必须能够比较大小和判等操作。这一条件构成了有序向量中“次序”概念的基础,否则所谓的“有序”将无从谈起。

复杂数据对象应重载"<“和”<="等操作符。

2.有序性甄别

在这里插入图片描述
算法思想:顺序扫描整个向量,逐一比较每一对相邻元素——向量已经有序,当且仅当它们都是顺序的。

template <typename T> 
int Vector<T>::disordered() const { //返回向量中逆序相邻元素对的总数int n = 0; //计数器for ( int i = 1; i < _size; i++ ) //逐一检查_size - 1对相邻元素if ( _elem[i - 1] > _elem[i] ) n++; //逆序则计数return n; //向量有序当且仅当n = 0
}

3.唯一化

出于效率的考虑,为清除无序向量中的重复元素,一般做法往往是首先将其转化为有序向量

3.1低效算法

3.1.1实现

算法思想:
在这里插入图片描述

template <typename T> 
int Vector<T>::uniquify() { //有序向量重复元素剔除算法(低效版)int oldSize = _size; int i = 1; //当前比对元素的秩,起始于首元素while ( i < _size ) //从前向后,逐一比对各对相邻元素_elem[i - 1] == _elem[i] ? remove ( i ) : i++; //若雷同,则初除后者;否则,转至后一元素return oldSize - _size; //向量觃模发化量,即被初除元素总数
}

3.1.2 复杂度

在这里插入图片描述
分析需用结论:remove()操作的复杂度线性正比于被删除元素的后继元素总数。不清除的可看无序向量。

最坏情况下:
当所有元素均雷同时,用于所有这些remove()操作的时间总量将高达:
(n - 2) + (n - 3) + … + 2 + 1= O( n 2 n^2 n2) 由算术级数得 。不清楚可看算法分析

这一效率竟与向量未排序时相同,说明该方法未能充分利用此时向量的有序性。

3.1.3 改进思路

反思:低效的根源在于,同一元素可作为被删除元素的后继多次前移
启示:若能以重复区间为单位,成批删除雷同元素,性能必能改进。

3.2 高效算法

3.2.1 实现

算法思想:
可以区间为单位成批地删除前后紧邻的各组重复元素,并将其后继元素(若存在)统一地大跨度前移。

template <typename T> 
Rank Vector<T>::uniquify() { //有序向量重复元素剔除算法(高效版)Rank i = 0, j = 0; //各对互异“相邻”元素的秩while ( ++j < _size ) //逐一扫描,直至末元素if ( _elem[i] != _elem[j] ) //跳过雷同者_elem[++i] = _elem[j]; //发现不同元素时,向前移至紧邻于前者右侧_size = ++i; shrink(); //直接截除尾部多余元素return j - i; //向量规模变化量,即被删除元素总数
}

3.2.2 复杂度

在这里插入图片描述
由此可知,uniquify()算法的时间复杂度应为O(n),较之无序向量唯一化算法的O( n 2 n^2 n2),效率整整提高了一个线性因子。关键在于向量已经排序

4.查找

4.1统一接口

为区别于无序向量的查找接口find(),有序向量的查找接口将统一命名为search()。外部接口形式上统一,内部实现算法却不见得完全统一。

template <typename T> //在有序向量的区间[lo, hi)内,确定不大于e的最后一个节点的秩
Rank Vector<T>::search( T const& e, Rank lo, Rank hi ) const { // 0 <= lo < hi <= _sizereturn ( rand() % 2 ) ? binSearch( _elem, e, lo, hi ) : fibSearch( _elem, e, lo, hi );
} //等概率地随机使用二分查找、Fibonacci查找
  • 如何处理特殊情况?
    比如,目标不存在;或者反过来,目标元素同时存在多个

4.2 语义定义

在语义上进一步的细致约定,使search()接口作为一个基本部件为其他算法利用。

在有序向量区间V[lo,hi)中,确定不大于e的最后一个元素。
在这里插入图片描述

4.3 二分查找

4.3.1 原理

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

4.3.2 实现

//二分查找算法(版本A):在有序向量的区间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
template <typename T> static Rank binSearch( T* S, T const& e, Rank lo, Rank hi ) {/*DSA*/printf ( "BIN search (A)\n" );while ( lo < hi ) { //每步迭代可能要做两次比较判断,有三个分支/*DSA*/ for ( int i = 0; i < lo; i++ ) printf ( "     " ); if ( lo >= 0 ) for ( int i = lo; i < hi; i++ ) printf ( "....^" ); printf ( "\n" );Rank mi = ( lo + hi ) >> 1; //以中点为轴点(区间宽度折半,等效于其数值表示的右移一位)if      ( e < S[mi] ) hi = mi; //深入前半段[lo, mi)继续查找else if ( S[mi] < e ) lo = mi + 1; //深入后半段(mi, hi)继续查找else                  return mi; //在mi处命中/*DSA*/ if ( lo >= hi ) { for ( int i = 0; i < mi; i++ ) printf ( "     " ); if ( mi >= 0 ) printf ( "....|\n" ); else printf ( "<<<<|\n" ); }} //成功查找可以提前终止return -1; //查找失败
} //有多个命中元素时,不能保证返回秩最大者;查找失败时,简单地返回-1,而不能指示失败的位置

通过快捷的整数移位操作回避了相对更加耗时的除法运算。
另外,通过引入lo、hi和mi等变量,将减治算法通常的递归模式改成了迭代模式。(递归消除)

4.3.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))。

4.3.4 查找长度

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

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

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

  • 成功查找长度

等概率条件下考查长度为n = 2 k 2^k 2k- 1的有序向量,并将其对应的平均成功查找长度记作 c a v e r a g e c_{average} caverage(k),将所有元素对应的查找长度总和记作C(k) = c a v e r a g e c_{average} caverage(k)∙( 2 k 2^k 2k- 1)。
~~~~~~~~~~~            当k = 1时向量长度n = 1,成功查找仅有一种情况
~~~~~~~~~~~~~~~~~~~~~~~~~                           c a v e r a g e c_{average} caverage(1) = C(1) = 2
对于长度为n = 2 k 2^k 2k- 1的有序向量,每步迭代都有三种可能的分支:经过1次成功的比较后,转化为一个规模为 2 k − 1 2^{k-1} 2k1- 1的新问题(左侧分支);经2次失败的比较后,终止于向量中的某一元素,并确认在此处成功中;经1次失败的比较另加1次成功的比较后,转化为另一个规模为 2 k − 1 2^{k-1} 2k1- 1的新问题(右侧分支)。
递推公式:
C(k) = [C(k - 1) + ( 2 k − 1 2^{k-1} 2k1- 1)] + 2 + [C(k - 1) + 2*( 2 k − 1 2^{k-1} 2k1- 1)] = 2∙C(k - 1) + 3* 2 k − 1 2^{k-1} 2k1- 1
令 F(k) = C(k) - 3k* 2 k − 1 2^{k-1} 2k1- 1
整理得: c a v e r a g e c_{average} caverage(k) = O(1.5∙log2n)

  • 失败查找长度

失败查找可能的情况,恰好比成功查找可能的情况多出一种。
1.5∙log2(n + 1) = O(1.5∙logn)

4.3.5 不足

尽管二分查找算法(版本A)即便在最坏情况下也可保证O(logn)的渐进时间复杂度,但就其常系数1.5而言仍有改进余地。见

4.4 Fibonacci查找

4.4.1 思路及原理

在这里插入图片描述调整前、后区域的宽度,适当地加长(缩短)前(后)子向量

4.4.2 实现

#include "fibonacci/Fib.h" //引入Fib数列类
//Fibonacci查找算法(版本A):在有序向量的区间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
template <typename T> static Rank fibSearch( T* S, T const& e, Rank lo, Rank hi ) {/*DSA*/printf ( "FIB search (A)\n" );//用O(log_phi(n = hi - lo)时间创建Fib数列for ( Fib fib( hi - lo ); lo < hi; ) { //Fib制表备查;此后每步迭代仅一次比较、两个分支/*DSA*/ for ( Rank i = 0; i < lo; i++ ) printf ( "     " ); if ( lo >= 0 ) for ( Rank i = lo; i < hi; i++ ) printf ( "....^" ); else printf ( "<<<<|" ); printf ( "\n" );while ( hi - lo < fib.get() ) fib.prev(); //自后向前顺序查找(分摊O(1))Rank mi = lo + fib.get() - 1; //确定形如Fib(k)-1的轴点if      ( e < S[mi] ) hi = mi; //深入前半段[lo, mi)继续查找else if ( S[mi] < e ) lo = mi + 1; //深入后半段(mi, hi)继续查找else                  return mi; //在mi处命中/*DSA*/ if ( lo >= hi ) { for ( int i = 0; i < mi; i++ ) printf ( "     " ); if ( mi >= 0 ) printf ( "....|\n" ); else printf ( "<<<<|\n" ); }} //一旦找到,随即终止return -1; //查找失败
} //有多个命中元素时,不能保证返回秩最大者;失败时,简单地返回-1,而不能指示失败的位置

对Fib数不清楚得可以看fib
在这里插入图片描述
效率略有提高。

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

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

相关文章

【03-掌握Scikit-learn:深入机器学习的实用技术】

文章目录 前言数据预处理缺失值处理数据缩放特征选择模型训练参数调整模型评估总结前言 经过了对Python和Scikit-learn的基础安装及简单应用,我们现在将更深入地探究Scikit-learn的实用技术,以进一步提升我们的数据科学技能。在本文中,我们将涵盖数据预处理、特征选择、模型…

Qt中的 tableView 设置 二进制 十六进制 序号表头

二 进制序号 因为QTableView的垂直表头并不支持使用委托来自定义。 相反&#xff0c;可以通过将自定义的QWidget作为QHeaderView的标签来实现这一目标。 代码&#xff1a; #include <QApplication> #include <QMainWindow> #include <QVBoxLayout> #include …

企业微信hook接口协议,根据手机号搜索联系人

根据手机号搜索联系人 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信 请求示例 {"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","phoneNumber":"1357xxxx" } 返回示例 {"data&q…

opencv可视化图片-----c++

可视化图片 #include <opencv2/opencv.hpp> #include <opencv2/core.hpp> #include <filesystem>// 将数据类型转换为字符串 std::string opencvTool::type2str(int type) {std::string r;uchar depth type & CV_MAT_DEPTH_MASK;uchar chans 1 (typ…

rust是否可以用于8051单片机开发工作?

目前&#xff0c;Rust 在嵌入式领域的发展主要集中在一些常见的架构上&#xff0c;如ARM Cortex-M&#xff08;包括STM32系列&#xff09;、RISC-V等。我这里有一套嵌入式入门教程&#xff0c;不仅包含了详细的视频 讲解&#xff0c;项目实战。如果你渴望学习嵌入式&#xff0c…

递归、搜索与回溯算法:FloodFill 算法

例题一 算法思路&#xff1a; 可以利⽤「深搜」或者「宽搜」&#xff0c;遍历到与该点相连的所有「像素相同的点」&#xff0c;然后将其修改成指定的像素即可。 全局变量&#xff1a; int dx[4] { 0,0,1,-1 }, dy[4] { 1,-1,0,0 }; int m, n; int precolor;//记录原先的颜色…

debian和ubuntu的核心系统和系统命令的区别

Debian和Ubuntu虽然有很深的渊源&#xff0c;都是基于Debian的发行版&#xff0c;但它们在核心系统和系统命令上还是有一些差别的。以下是一些主要的不同之处&#xff1a; 1. 发布周期&#xff1a; - Debian&#xff1a; Debian项目采用滚动发布模型&#xff0c;持续更新&a…

CCF区块链会议--Middleware 2024 截止5.24 附录用率

会议名称&#xff1a;Middleware CCF等级&#xff1a;CCF B类会议 类别&#xff1a;软件工程/系统软件/程序设计语言 录用率&#xff1a;2022年录用率38%&#xff08;8/21&#xff09; Topics of Interest The Middleware conference seeks original submissions of resear…

【Linux网络】Linux网络设置

如果你不会网络设置&#xff0c;就好比自己的拖鞋被硬控了&#xff0c;导致自己无法下床 目录 一、网络配置 1.1 主要配置网络的配置项 1.2 ifconfig——查看网卡配置 1.3 route——路由 1.4 hostname——主机名 1.5 ss——查看网络链接状态 1.6 scp——远程拷贝 1.7 …

<网络> HTTP

目录 前言&#xff1a; 一、再谈协议 &#xff08;一&#xff09;认识URL &#xff08;二&#xff09;Encode 和 Decode 二、HTTP 协议 &#xff08;一&#xff09;协议格式 &#xff08;二&#xff09;见一见请求 &#xff08;三&#xff09;见一见响应 三、模拟实现响…

百度安全多篇议题入选Blackhat Asia以硬技术发现“芯”问题

Blackhat Asia 2024于4月中旬在新加坡隆重举行。此次大会聚集了业界最杰出的信息安全专业人士和研究者&#xff0c;为参会人员提供了安全领域最新的研究成果和发展趋势。在本次大会上&#xff0c;百度安全共有三篇技术议题被大会收录&#xff0c;主要围绕自动驾驶控制器安全、跨…

nvm的简介、安装、使用

一、nvm是什么&#xff1f; nvm是一个node的版本管理工具&#xff0c;可以简单操作node版本的切换、安装、查看。。。等等&#xff0c;与npm不同的是&#xff0c;npm是依赖包的管理工具。 二、nvm的安装。 2.1 nvm下载 安装包下载地址&#xff1a;https://github.com/coreyb…

共享单车(二):项目日志

stdin, stdout, stderr Linux系统下&#xff0c;当一个用户进程被创建时&#xff0c;与之对应的三个数据流&#xff08;stdin&#xff0c;stdout和stderr&#xff0c;即三个文件&#xff09;也会被创建。 stdin&#xff0c;标准输入文件&#xff0c;通常对应着终端的键盘。 s…

【C语言 |预处理指令】预处理指令详解(包括编译与链接)

目录 一、编译与链接 1.翻译环境 -预处理 -编译 -汇编 -链接 2.执行环境 二、预定义符号 三、#define定义常量 四、#define定义宏 五、带有副作用的宏参数 六、宏替换的规则 七、 宏函数的对比 八、#和## 1.#运算符 2.##运算符 九、命名约定 十、#undef 十一、 命…

IDEA本地将镜像推送到coding制品仓库

创建制品仓库 假设仓库名称为docker 在IDEA 添加Docker 注册表 IDEA必须先安装docker插件 地址 用户名和密码就是coding的登录名和密码服务器 最好本地安装docker桌面版&#xff0c;更容易操作 测试连接成功 推送镜像到coding的docker制品仓库 选中某个镜像 鼠标右键 注册表…

四.RocketMQ的几种消息发送方式应用

RocketMQ的几种消息发送方式应用 一&#xff1a;普通消息1&#xff09;发送同步消息2&#xff09;发送异步消息3&#xff09;单向发送消息4&#xff09;消费消息-负载均衡模式5&#xff09;消费消息-广播模式 二&#xff1a;顺序消息1.顺序消息指的是:严格按照消息的发送顺序进…

服务器数据恢复—ESXi无法识别数据存储和VMFS文件系统如何恢复数据?

服务器数据恢复环境&#xff1a; 一台某品牌服务器&#xff0c;通过FreeNAS来做iSCSI&#xff0c;然后使用两台同品牌服务器做ESXi虚拟化系统。 FreeNAS层为UFS2文件系统&#xff0c;使用整个存储建一个稀疏模式的文件&#xff0c;挂载到ESXi虚拟化系统。ESXi虚拟化系统中有3台…

react实现时钟翻牌效果

需求&#xff1a;随着数字的变动要求有时钟翻动动效 问题&#xff1a;只在加载时有动效 解决方案&#xff1a;通过判断数字改变&#xff08;这里通过新旧数值变动来判断&#xff0c;不贴代码啦&#xff09;&#xff0c;每次变动的时候手动把animationIterationCount设置为inf…

【blog项目】layui与jquery冲突导致鼠标悬停事件失效、如何调用layui.use()作用域里的方法

blog项目前台展示——查询数据库中的文章类型并展示时出现的bug 1 正常演示 2 用jquery查询数据库并添加到页面后 3 相关代码 <script src"/static/jquery-2.1.4.js"></script> <script src"/static/layui/layui.js"></script> …

分布式与一致性协议之CAP(一)

CAP理论 概述。 在开发分布式系统的时候&#xff0c;会遇到一个非常棘手的问题&#xff0c;那就是如何根据业务特点&#xff0c;为系统设计合适的分区容错一致性模型&#xff0c;以实现集群能力。这个问题棘手在当发生分区错误时&#xff0c;应该如何保障系统稳定运行而不影响…