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

文章目录

  • 0.概述
  • 1.元素访问
  • 2.置乱器
  • 3.判等器与比较器
  • 4.无序查找
    • 4.1 判等器
    • 4.2 顺序查找
    • 4.3 实现
    • 4.4 复杂度
  • 5. 插入
    • 5.1 算法实现
    • 5.2 复杂度分析
  • 6. 删除
    • 6.1 区间删除
    • 6.2 单元删除
    • 6.3 复杂度
  • 7. 唯一化
    • 7.1 实现
    • 7.2 正确性
    • 7.3 复杂度
  • 8. 遍历
    • 8.1 实现
    • 8.2 复杂度
  • 9. 总结

0.概述

记录向量的元素访问、插入、区间删除、单元素删除、查找、唯一化、遍历算法。

1.元素访问

重载操作符"[]",使元素访问更加便捷。
在这里插入图片描述

template <typename T> T & Vector<T>::operator[] ( Rank r ) //重载下标操作符
{ return _elem[r]; } // assert: 0 <= r < _size

template <typename T> const T & Vector<T>::operator[] ( Rank r ) const //仅限于做右值
{ return _elem[r]; } // assert: 0 <= r < _size

经重载后操作符“[]”返回的是对数组元素的引用,这就意味着它既可以取代get()操作(通常作为赋值表达式的右值),也可以取代set()操作(通常作为左值)。

2.置乱器

目标:借助操作符 “[]” 随机置乱向量,使各元素等概率出现于各位置。
策略:自后向前,依次将各元素与随机选取的某一前驱(含自身)做交换

template <typename T> void permute ( Vector<T>& V ) { //随机置乱向量,使各元素等概率出现于各位置
   for ( int i = V.size(); i > 0; i-- ) //自后向前
      swap ( V[i - 1], V[rand() % i] ); //V[i - 1]与V[0, i)中某一随机元素交换
}

从待置乱区间的末元素开始,逆序地向前逐一处理各元素。
在这里插入图片描述
注意,这里的交换操作swap(),隐含了三次基于重载操作符“[]”的赋值。

  • 通过反复调用 permute()算法,可以生成向量 V[0, n)的所有 n!种排列。
  • 由该算法生成的排列中,各元素处于任一位置的概率均为 1/n
  • 该算法生成各排列的概率均为 1/n!

3.判等器与比较器

算法思想:

  • 可比较或可比对的任何数据类型,而不必关心如何定义以及判定其大小或相等关系。
  • 将比对和比较操作的具体实现剥离出来,直接讨论算法流程本身。
  • 在定义对应的数据类型时,通过重载"<“和”=="之类的操作符,给出大小和相等关系的具体定义及其判别方法。
template <typename T> static bool lt ( T* a, T* b ) { return lt ( *a, *b ); } //less than
template <typename T> static bool lt ( T& a, T& b ) { return a < b; } //less than
template <typename T> static bool eq ( T* a, T* b ) { return eq ( *a, *b ); } //equal
template <typename T> static bool eq ( T& a, T& b ) { return a == b; } //equal

在一些复杂的数据结构中,内部元素本身的类型可能就是指向其它对象的指针;而从外部更多关注的,则往往是其所指对象的大小。若不加处理而直接根据指针的数值(即被指对象的物理地址)进行比较,则所得结果将毫无意义。

4.无序查找

4.1 判等器

Vector::find(e)接口,功能语义为“查找与数据对象e相等的元素”。这同时也暗示着,向量元素可通过相互比对判等,但未必支持比较的向量,称作无序向量(unsorted vector)

4.2 顺序查找

在这里插入图片描述
从末元素起自后向前,逐一取出各个元素并与目标元素e进行比对,直至发现与之相等者(查找成功),或者直至检查过所有元素之后仍未找到相等者(查找失败)。这种依次逐个比对的查找方式,称作顺序查找

4.3 实现

template <typename T> //在无序向量中顺序查找e:成功则返回最靠后的出现位置,否则返回lo-1
Rank Vector<T>::find ( T const& e, Rank lo, Rank hi ) const { //0 <= lo < hi <= _size
   while ( ( lo < hi-- ) && ( e != _elem[hi] ) ); //从后向前,顺序查找
   return hi; //若hi < lo,则意味着失败;否则hi即命中元素的秩
}

细节:

  • 当同时有多个命中元素时,统一约定返回其中秩最大者
  • while循环的控制逻辑由两部分组成,首先判断是否已抵达lo,再判断当前元素与目标元素是否相等。得益于C/C++语言中逻辑表达式的短路求值特性,在前一判断非真后循环会立即终止,而不致因试图引用已越界的秩(-1)而出错。

4.4 复杂度

最坏情况 查找终止于首元素_elem[lo],运行时间为O(hi - lo) = O(n)。
最好情况 查找命中于末元素_elem[hi - 1],仅需O(1)时间。
对于规模相同、内部组成不同的输入,渐进运行时间却有本质区别,故此类算法也称作输入敏感的算法

5. 插入

5.1 算法实现

算法思想:插入之前必须首先调用expand()算法,核对是否即将溢出。

template <typename T> //将e插入至[r]
Rank Vector<T>::insert ( Rank r, T const& e ) { //0 <= r <= size
   expand(); //如必要,先扩容
   for ( Rank i = _size; r < i; i-- ) //自后向前,后继元素
      _elem[i] = _elem[i-1]; //顺次后移一个单元
   _elem[r] = e; _size++; //置入新元素并更新容量
   return r; //返回秩
}

在这里插入图片描述
为保证数组元素物理地址连续的特性,随后需要将后缀_elem[r, _size)(如果非空)整体后移一个单元(图©)。这些后继元素自后向前的搬迁次序不能颠倒,否则会因元素被覆盖而造成数据丢失。在单元_elem[r]腾出之后,方可将待插入对象e置入其中(图(d))。

5.2 复杂度分析

时间主要消耗于后继元素的后移,线性正比于后缀的长度,故总体为O(_size - r + 1)。
r取最大值_size时为最好情况,只需O(1)时间;r取最小值0时为最坏情况,需要O(_size)时间。

若插入位置等概率分布,则平均运行时间为O(_size) = O(n)

运行时间主要来自于后继元素顺次后移的操作。因此对于每个插入位置而言,对应的移动操作次数恰好等于其后继元素(包含自身)的数目。不难看出它们也构成一个等差数列(数学期望O( n 2 n^2 n2) m为后继元素数目),故在等概率的假设条件下,其均值(数学期望)应渐进地与其中的最高项同阶,为O(n)。

6. 删除

应将单元素删除视作区间删除的特例,并基于后者来实现前者

6.1 区间删除

template <typename T> Rank Vector<T>::remove( Rank lo, Rank hi ) { //0 <= lo <= hi <= n
   if ( lo == hi ) return 0; //出于效率考虑,单独处理退化情况
   while ( hi < _size ) _elem[lo++] = _elem[hi++]; //后缀[hi, _size)顺次前移hi-lo位
   _size = lo; shrink(); //更新规模,lo=_size之后的内容无需清零;如必要,则缩容
   //若有必要,则缩容
   return hi - lo; //返回被删除元素的数目
}

在这里插入图片描述
设[lo, hi)为向量(图(a))的合法区间(图(b)),则其后缀[hi, n)需整体前移hi - lo个单元(图©)。与插入算法同理,后继元素自前向后的移动次序也不能颠倒。

  • 若以自后向前得次序逐个前移后继元素,位置靠前的元素,可能被位置靠后(优先移动)的元素覆盖,从而造成数据的丢失。
    在这里插入图片描述
    V.remove(0, 2)以删除其中的前两个元素,可见,原数据元素V[2] = 2并未顺利转移至输出向量中的V[0],即出现数据的丢失现象。

6.2 单元删除

重载即可实现如下另一同名接口remove( r )。

template <typename T> T Vector<T>::remove( Rank r ) { //删除向量中秩为r的元素,0 <= r < size
   T e = _elem[r]; //备份被删除元素
   remove( r, r + 1 ); //调用区间删除算法,等效于对区间[r, r + 1)的删除
   return e; //返回被删除元素
}

6.3 复杂度

remove(lo, hi)的计算成本,主要消耗于后续元素的前移,线性正比于后缀的长度,总体不过O(m + 1) = O(_size - hi + 1)。
结论

区间删除操作所需的时间,应该仅取决于后继元素的数目,而与被删除区间本身的宽度无关。

被删除元素在向量中的位置越靠后(前)所需时间越短(长),最好为O(1),最坏为O(n) = O(_size)。

7. 唯一化

所谓向量的唯一化处理,就是剔除其中的重复元素。

7.1 实现

算法思想:该算法自前向后逐一考查各元素_elem[i],并通过调用find()接口,在其前缀中寻找与之雷同者。若找到,则随即删除;否则,转而考查当前元素的后继。

template <typename T> Rank Vector<T>::dedup() { //删除无序向量中重复元素(高效版)
   Rank oldSize = _size; //记录原规模
   for ( Rank i = 1; i < _size; ) //自前向后逐个考查_elem[1,_size)
      if ( -1 == find(_elem[i], 0, i) ) //在前缀[0,i)中寻找与[i]雷同者(至多一个),O(i)
         i++; //若无雷同,则继续考查其后继
      else
         remove(i); //否则删除[i],O(_size-i)
   return oldSize - _size; //被删除元素总数
}

7.2 正确性

在while循环中,在当前元素的前缀_elem[0, i)内,所有元素彼此互异
在这里插入图片描述

7.3 复杂度

随着循环的不断进行,当前元素的后继持续地严格减少

这里所需的时间,主要消耗于find()和remove()两个接口。

find()时间应线性正比于查找区间的宽度,即前驱的总数;
remove()时间应线性正比于后继的总数。因此,每步迭代所需时间为O(n),总体复杂度应为O( n 2 n^2 n2)。

8. 遍历

8.1 实现

算法思想:

  1. 借助函数指针*visit()指定某一函数,该函数只有一个参数,其类型为对向量元素的引用,故通过该函数即可直接访问或修改向量元素。
  2. 也可以函数对象的形式,指定具体的遍历操作。这类对象的操作符“()”经重载之后,在形式上等效于一个函数接口,故此得名。
    在这里插入图片描述
template <typename T> void Vector<T>::traverse( void ( *visit )( T& ) ) //借助函数指针机制
{ for ( Rank i = 0; i < _size; i++ ) visit( _elem[i] ); } //遍历向量

template <typename T> template <typename VST> //元素类型、操作器
void Vector<T>::traverse( VST& visit ) //借助函数对象机制
{ for ( Rank i = 0; i < _size; i++ ) visit( _elem[i] ); } //遍历向量

相比较而言,后一形式的功能更强,适用范围更广。

比如,函数对象的形式支持对向量元素的关联修改。也就是说,对各元素的修改不仅可以相互独立地进行,也可以根据某个(些)元素的数值相应地修改另一元素。前一形式虽也可实现这类功能,但要繁琐很多。

例如:统一递增向量中的各元素

template <typename T> void increase ( Vector<T> & V ) //统一递增向量中的各元素
{  V.traverse ( Increase<T>() );  } //以Increase<T>()为基本操作进行遍历

8.2 复杂度

遍历操作本身只包含一层线性的循环迭代,故除了向量规模的因素之外,遍历所需时间应线性正比于所统一指定的基本操作所需的时间。故这一遍历的总体时间复杂度为O(n)。

9. 总结

  1. 置乱算法 permute() 从待置乱区间的末元素开始,逆序地向前逐一处理各元素。时间复杂度为O(n)
  2. 顺序查找算法 find() 从末元素起自后向前,逐一取出各个元素并与目标元素进行比对,时间复杂度应线性正比于查找区间的宽度,即前驱的总数。
  3. 插入算法insert() ,时间复杂度线性正比于后缀的长度为
  4. 删除算法remove() ,时间复杂度应该仅取决于后继元素的数目
  5. 唯一化算法deduplicate(),主要消耗于find()和remove()两个接口,时间复杂度O( n 2 n^2 n2),可以继续改进。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue3引入图片 无法使用require, vue3+vite构建项目使用require引入包出现问题需要用newURL来动态引入图片等静态资源

在vue3中 require引入图片的本地资源报错Uncaught (in promise) ReferenceError: require is not defined <template> <img :src"imageSrc" alt"My Image"> </template> <script> import imageSrc from /assets/image.png; export…

多媒体技术如何为地震体验馆增添更多真实元素?

近年来&#xff0c;为提升公众安全意识&#xff0c;众多体验式科普展馆纷纷崭露头角&#xff0c;其中地震体验馆尤为引人瞩目&#xff0c;成为学校安全教育的热门场景&#xff0c;接下来&#xff0c;我们就深入探索一下&#xff0c;这种运用了多媒体技术的地震体验馆&#xff0…

有哪些好用的电商API接口(京东|天猫|淘宝商品详情数据接口)

此API目前支持以下基本接口&#xff1a; 如何获取此API测试权限&#xff1f; item_get 获得淘宝商品详情item_get_pro 获得淘宝商品详情高级版item_review 获得淘宝商品评论item_fee 获得淘宝商品快递费用item_password 获得淘口令真实urlitem_list_updown 批量获得淘宝商品上…

云计算中的过度授权:安全隐患与应对策略

云计算凭借其弹性、可扩展等优势&#xff0c;已经成为诸多企业组织拓展业务的重要基础设施之一。然而&#xff0c;与传统IT架构相比&#xff0c;云计算环境的安全管理也面临着新的挑战。过度授权 (Overprivileging) 便是云安全领域亟待解决的主要问题之一&#xff0c;本文将带领…

开源模型应用落地-LangChain高阶-知识图谱助力记忆增强

一、前言 通过langchain框架调用本地模型&#xff0c;使得用户可以直接提出问题或发送指令&#xff0c;而无需担心具体的步骤或流程。langchain会自动将任务分解为多个子任务&#xff0c;并将它们传递给适合的语言模型进行处理。 本篇通过使用 ConversationKGMemory 组件&#…

MySQL简解

文章目录 1. MySQL框架2. 执行流程2.1. 连接池&#xff1a;2.2. SQL 前端(SEVER)2.2.0. 查询缓存2.2.1. SQL 接口2.2.2. SQL 解析器2.2.3. SQL 执行器2.2.4. INNODB 中读写操作 2.3. 数据的保存形式 3.其他重要概念3.1. 索引3.1.1. 简单概念3.1.2. 索引优化&#xff1a;1. Usin…

【复现代码——环境配置】

目录 一、复现代码举例二、创建环境——选择一个Python版本2.1 创建基本环境2.1.1 基于AutoDL2.1.2 基于PyCharm 2.2 终端激活环境2.3 退出环境2.4 删除环境 三、PyTorch安装3.1 查看cuda3.2 安装PyTorch 四、其他依赖安装4.1 tensorboardX4.2 matplotlib4.3 medpy4.4 visdom4.…

stable-diffusion-webui安装与使用过程中的遇到的error合集

stable-diffusion-webui1.9.2踩坑安装 1. 安装过程1.1 stable-diffusion-webui1.2 在win11或win10系统安装&#xff0c;需修改两个启动脚本1.2.1 修改webui-user.bat1.2.2 修改webui.bat 1.3 双击 webui-user.bat 启动脚本1.3.1 no module xformers. Processing without on fre…

实体书营销:“三三裂变”,实操细节分享……

实体书营销:“三三裂变”,实操细节分享 一、实验结果 “三三裂变”的实验,结果比较好。就是我们大概有300人报名,但实际行动的只有109人,大概有103人都完成了三个人的目标,也就是说我们通过109人裂变了475人,利润率是1:4.5左右,整个裂变的效率还是可以的,也就是说: …

阿赵UE学习笔记——30、HUD简单介绍

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   继续学习虚幻引擎&#xff0c;这次来学习一下HUD的基础使用。 一、 什么是HUD HUD(Head-Up Display)&#xff0c;也就是俗称的抬头显示。很多其他领域里面有用到这个术语&#xff0c;比如开车的朋友可能会接触过&#xf…

后端工程师——Java工程师岗位要求

在国内,Java 程序员是后端开发工程师中最大的一部分群体,其市场需求量也是居高不下,C++ 程序员也是热门岗位之一,此二者的比较也常是热点话题,例如新学者常困惑的问题之一 —— 后端开发学 Java 好还是学 C++ 好。读完本文后,我们可以从自身情况、未来的发展,岗位需求量…

适用于手机蓝牙的热敏晶体FA1612AS

EPSON推出的一款1612小尺寸无源热敏晶体:FA1612AS。FA1612AS的额定频率为38.4Mhz的晶体单元&#xff0c;采用无铅材料&#xff0c;符合ROHS标准&#xff0c;内置热敏电阻&#xff0c;可用于移动电话&#xff0c;蓝牙等。热敏晶体FA1612AS的产品特性:额定频率:38.4MHZ外部尺寸规…

上海亚商投顾:沪指缩量调整 有色、煤炭等周期股集体大跌

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日缩量调整&#xff0c;午后一度跌近1%&#xff0c;黄白二线走势分化&#xff0c;微盘股指数涨超3%。军…

SpringBoot 启动控制台 --banner.txt实现打印炫酷控制台图案

文章目录 目录 文章目录 安装流程 小结 概要安装流程技术细节小结 概要 分析源代码&#xff0c;banner.txt实现打印控制台 控制台图案生成网址&#xff1a;Ascii艺术字实现个性化Spring Boot启动banner图案&#xff0c;轻松修改更换banner.txt文件内容&#xff0c;收集了丰富…

ASP.NET Core 3 高级编程(第8版) 学习笔记 04

第 19 章主要介绍 Restful Service 的相关知识。Restful Service 的核心内容是&#xff1a;&#xff08;1&#xff09;HTTP 请求或 HTTP 动词&#xff0c;用 HTTP 请求表达不同的操作&#xff0c;最好遵守惯例。&#xff08;2&#xff09;资源&#xff0c;通过 PATH 结合 paylo…

C语言学习/复习31--简单通讯录功能的实现/结构体的运用/strcmp函数的运用/memset函数

0、分文件/结构体定义初始化/成员变量的访问/结构体地址传参/switch/for()/do while()/数组中元素的添加与删除/assert/const/宏/字符与内存函数 一、结构体运用---通讯录 1.基本功能 2.项目文件 二.具体操作方法 1.test.c文件 包含菜单与输入界面 2.contact.h头文件 …

中霖教育:二建考试哪些地区查社保?

想要报考二级建造师考试的同学都知道&#xff0c;在个别省份报名参加二建是需要核查社保信息的&#xff0c;也有一些省份对社保不做强制要求。 以下这几个省份查社保&#xff0c;如果不满足条件可以避开这几个省份&#xff0c;具体规定可参考当地发布的二建考试公告。 山东、…

阿里云官方综合优惠平台,官方云小站平台最新优惠政策汇总

阿里云官方云小站平台是阿里云为用户提供的优惠聚集地&#xff0c;这里不仅有丰富的优惠活动&#xff0c;还有不定期发布的云产品通用代金券。本文为您详细介绍阿里云官方综合优惠平台——官方云小站2024年的最新优惠政策&#xff0c;帮助您以更优惠的价格享受到高品质的云服务…

影响肉类口感的关键指标:肉嫩度的深度解析与检测方法

影响肉类口感的关键指标&#xff1a;肉嫩度的深度解析与检测方法 一、引言&#xff1a;肉类嫩度与食用体验 在饮食文化中&#xff0c;肉类的嫩度一直被视为影响口感的重要因素。对于消费者而言&#xff0c;嫩滑多汁的肉质往往能带来更好的食用体验。因此&#xff0c;准确评估…

如何在官网查看Qt5的所有模块?

2024年4月23日&#xff0c;周二上午 如果你不想一步步来的话&#xff0c;可以直接去这个Qt官方链接 https://doc.qt.io/qt-5/qtmodules.html 第一步&#xff1a;去到Qt官网 https://www.qt.io/ 第二步&#xff1a;点击文档链接 第三步&#xff1a;选择文档中的“Qt5” 第四步…