C++学习笔记(十六):对vector进行更多的操作——泛型算法

先强调一下,这里的泛型算法实际不光光是对vector的操作,对于“顺序容器”均可以。

但是什么是顺序容器:

我们都知道,容器就是一些特定类型对象的集合。而顺序容器为程序员提供了控制元素存储和访问的能力。这种容器的一个显著的特征,就是容器中元素的顺序不依赖于元素的值,而是与加入容器时的位置有关。常见的顺序容器有vector、deque(双端队列)、list(双向链表)、forward_list(单向链表)、array(固定大小数组)、string。

了解了顺序容器,现在以vector为例,做下文的说明。

顺序容器本身只定义了很少的操作,这些操作我在前面的博客(点这里)也有写过。比如添加、删除元素,访问元素、获得迭代器等。但是现实中,我们用户肯定希望有更多的操作供自己使用,比如查找、替换、删除特定元素,重新排列元素等。为了实现上面的功能,程序员可能需要写一大段代码来将其实现。

为了解决这个问题,增加对于vector的操作种类,标准库给出了一组“泛型算法(generic algorithm)”。称其“算法”,是因为他们实现了一些经典算法的公共接口,比如排序、搜索。称其为“泛型”,是因为他们可以用于不同类型的元素和多种容器类型。

下面讲一下具体有哪些泛型算法。

大多数的算法都定义在头文件algorithm中,标准库还在头文件numeric中定义了一组数值泛型算法。一般情况下这些算法并不直接操作容器,而是遍历由两个迭代器指定的一个元素范围。

这些算法大致可以分为下面几类:

一、只读算法

顾名思义,这种算法只读取其输入范围内的元素,并不改变元素。

<1>find(vec.begin() , vec.end(), val)

在vec中搜索val,返回第一个等于val的元素的迭代器。如果范围内无匹配元素,则放回vec.end()。

<2>count(vec.begin() , vec.end(), val)

在vec中搜索val,返回val在vec中出现的次数。

<3>accumulate(vec.begin() , vec.end(), val)

在vec中的元素求和,和的初始值设为val。val的类型决定了函数使用哪个加法运算符以及返回值类型。

<4>equal(vec1.begin() , vec1.end(), vec2.begin())

比较两个vector是否相等,返回值为bool型。

二、写容器元素算法

<1>fill(vec.begin(), vec.end(), val)

将vec中的元素重置为val

<2>fill_n(dest , n , val)

将从dest开始的n个元素重置为val。这里的dest是一个指向某个元素的迭代器。注意:这里的vec不能是空的,如果是空,那么上面的操作将会出现未知结果。

<3>back_inserter(vec)

向容器中添加元素的迭代器,故称之为插入迭代器。通常来说,当我们通过迭代器来给容器赋值时,值被赋予迭代器指向的元素。而当我们通过一个插入迭代器赋值时,一个与赋值号右侧值相等的元素被添加到容器中。back_inserter接收一个指向容器的引用,返回一个与该容器绑定的插入迭代器。当我们通过此迭代器赋值时,赋值运算符会调用push_back将一个具有给定值的元素添加到容器中。比如:

vector<int> vec;  //空向量

auto it = back_inserter(vec);  //通过它赋值会将元素添加到vec中

*it = 42;   //vec中现在有一个元素,值为42

我们常常使用back_inserter来创建迭代器,作为泛型算法的目的位置使用。比如:

vector<int> vec;   //空向量

fill_n(back_inserter(vec), 10 ,0);  //添加10个元素到vec。

可以发现,前面说fill_n的vec不能为空,否则将会出现未知结果,而这里back_inserter相当于给vec push_back 了10个位置,然后填充,故这里的用法是可以的。

<4>copy(vec1.begin(), vec1.end(), vec2.begin())

将vec1中的内容拷贝到vec2中,故这里要求vec2的长度必须要大于等于vec1的长度。

<5>replace(vec.begin(), vec.end(), val1 ,val2)

将vec中的所有val1都替换为val2。

<6>replace_copy(vec1.begin(), vec1.end(),vec2.begin(), val1 ,val2)

替换后vec1中的值并未改变,而是将vec1拷贝到vec2中,并将vec2中的所有val1都替换为val2。

三、排序

sort(vec.begin() , vec.end());

对vec中的内容按字典顺序排序

四、删除相同数据

unique(vec.begin(), vec.end());

将vec中重复的数据删除,返回指向不重复区域之后一个位置的迭代器。值得注意的是这个删除操作只是将vec中的数据清空,但是vec的大小不变。即假设原vec中有40个元素,其中重复的有5个,那么经过unique操作后,这些重复元素重复的部分就不见了,vec中非空数据变成了35个,剩下的5个空间里面的数据为空。但是vec的size仍旧为40。要想真正的删除这些元素,还需用到容器本身的操作,erase。

时间: 2025-01-17 04:48:54

C++学习笔记(十六):对vector进行更多的操作——泛型算法的相关文章

C++学习笔记十六-模板和泛型编程(二)

C++学习笔记十六-模板和泛型编程(二) 16.4 类模板成员 1.模板作用域中模板类型的引用: 通常,当使用类模板的名字的时候,必须指定模板形参.这一规则有个例外:在类本身的作用域内部,可以使用类模板的非限定名.例如,在默认构造函数和复制构造函数的声明中,名字 Queue 是 Queue<Type> 缩写表示.实质上,编译器推断,当我们引用类的名字时,引用的是同一版本.因此,复制构造函数定义其实等价于: Queue<Type>(const Queue<Type> &a

MYSQL进阶学习笔记十六:MySQL 监控!(视频序号:进阶_35)

知识点十六:MySQL监控(35) 一.为什么使用MySQL监控 随着软件后期的不断升级,myssql的服务器数量越来越多,软硬件故障的发生概率也越来越高.这个时候就需要一套监控系统,当主机发生异常时,此时通过监控系统发现和处理. 这个监控实际上是在我们的开发完成之后,这个时候软件就开始在运行,这个运行我们就需要去关注到mysql服务器是否正常,那么我们要观察它就需要给它提供一些监控,这监控就是当它发生故障之后, 那么我们这个监控就会告诉我们到底什么地方发生了一些异常或者一些错误,这个时候我们就

Java基础学习笔记十六 集合框架(二)

List List接口的特点: 它是一个元素存取有序的集合.例如,存元素的顺序是11.22.33.那么集合中,元素的存储就是按照11.22.33的顺序完成的. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理). 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素. List接口的常用子类有: ArrayList集合 LinkedList集合 List接口的特有方法(带索引的方法)1.增加元素方法 add(Object e):向集合末尾

python学习笔记十六 django深入学习一

django 请求流程图 django 路由系统 在django中我们可以通过定义urls,让不同的url路由到不同的处理函数 from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), #精确匹配 url(r'^articles/([0-9]{4})/$', views.year_archive), #动态路由 url(r'^articles/([0-9]{4})/([0-9]{2

spring in action学习笔记十六:配置数据源的几种方式

第一种方式:JNDI的方式. 用xml配置的方式的代码如下: 1 <jee:jndi-lookup jndi-name="/jdbc/spittrDS" resource-ref="true" id="dataSource"/> 用注解方式的代码如下: 1 @Bean 2 public JndiObjectFactoryBean jndiObjectFactoryBean(){ 3 JndiObjectFactoryBean jndi

yii2源码学习笔记(十六)

Module类的最后代码 1 /** 2 * Registers sub-modules in the current module. 3 * 注册子模块到当前模块 4 * Each sub-module should be specified as a name-value pair, where 5 * name refers to the ID of the module and value the module or a configuration 6 * array that can

[傅里叶变换及其应用学习笔记] 十六. 继续上次内容,晶体成像

x射线晶体照像术 1) x射线是1895年由伦琴(Roentgen)发现的,其波长为$10^{-8}$厘米左右,常用的测量可见光波长的方法会由于其波长太小而无法测量. 2) 晶体(Crystals),晶体的原子结构符合一定规律——原子有序地排列成晶格.劳厄(Laue)在1912年做了一系列著名实验,其目的是利用x射线进行衍射实验来研究晶体的本质. 劳尔假设: 1) x射线是波,因此可以进行衍射 2) 晶体可以充当合适的衍射光栅,即晶体具有晶格原子(lattice atomic)——周期性的原子结

JavaScript权威设计--CSS(简要学习笔记十六)

1.Document的一些特殊属性 document.lastModified document.URL document.title document.referrer document.domain document.write() document.writeIn() 2.查询选取的文本 使用鼠标mouseup事件 3.浏览器定义了多项文本编辑命令(富文本编辑器) 使用Document对象的execCommand()方法. document.queryCommandSupport()判断浏

Android学习笔记十六.Android数据存储与IO.SharedPreferences

SharedPreferences 对于应用程序的数据输入.输出,如果是应用程序只是少量数据需要保存,那么使用普通文件就可以了(SharedPrefereces);但如果应用程序有大量数据需要存储.访问,就需要借助数据库了.Android系统内置了SQLite数据库,SQLite数据库是一个真正轻量级的数据库,它没有后台进程,整个数据库就对应于一个文件. 1.SharedPreferences简介 (1)概念:SharedPreferences保存的数据主要是类似于配置信息格式的数据,因此它保存