C++Primer笔记之顺序容器的使用详解_C 语言

  顺序容器,它将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素,这就是顺序容器。标准库里定义了三种类型:vector(支持快速随机访问)、list(支持快速插入、删除)、deque(双端队列)容器只定义了少量操作,大多数额外的操作由算法库提供。容器内元素的类型约束;1、元素类型必须支持赋值运算;2、元素类型的对象必须可以复制。这是容器元素类型的最低要求,如果想支持一些其他特殊要求,则必须具备相关的性质。

可以定义容器的容器vector< vector<int> > lines;//必须使用"> >"中间的空格,否则会出现变异错误

迭代器运算:

  关系操作符只适用于vector和deque容器,它们可以根据元素位置直接有效地访问指定的容器元素。而list容器的迭代器既不支持算术运算(加法或者减法),也不支持关系运算(<=,<,>=,>),它只提供前置和后置的自增、自减运算以及相等(不等)运算。

迭代器范围:

  c++使用一对迭代器标记迭代器范围,通常命名为first和last或beg和end。该范围内的元素包括迭代器first指向的元素,以及从first开始一直到迭代器last指向的位置之前的所有元素,此类元素范围称为左闭合区间[first,last)。

顺序容器的操作:

  在容器中添加元素;在容器中删除元素;设置容器大小;获取容器内的第一个和最后一个元素。对于begin()、end()、rbegin()、 rend()四个操作,均有const版本。如果容器时const,则其返回类型要加上const_前缀。c.push_back(t) 在容器c的尾部添加值为t的元素,返回void类型。c.push_front(t) 在容器c的前端添加值为t的元素,返回void类型。但是只有list和deque具有这样的性质。

复制代码 代码如下:

//容器的顺序遍历
vector<int>::reverse_iterator iterReverse=vect.rbegin();//定义反向迭代器while(iterReverse!=vect.rend())
{
    cout<<*iterReverse<<endl;
    iterReverse++;
}
vector<int>::iterator iter = vect.begin();//定义正向迭代器
while(iter!=vect.end())
{
    cout<<*iter<<endl;
    iter++;
}

  在容器中的指定位置添加元素:使用insert函数:由于迭代器可能指向超出容器末端的下一位置没这事一个不存在的元素,因此insert函数是在其指向位置之前而非其后插入元素。mylist.insert(iter,element);

复制代码 代码如下:

//获取中心位置迭代器,需要注意的list不允许如下的迭代器的加法
vector<int>::iterator middle=vectCpy.begin()+vect.size()/2;
vectCpy.insert(middle,1001);//在中间位置添加一个元素 

  插入一段元素:

复制代码 代码如下:

vectCpy.insert(vectCpy.begin(),10,9);//在第一个元素后面添加10个初值为9的元素
int num[3]={555,666,777};
vectCpy.insert(vectCpy.end(),num,num+3);//在vectCpy后面加入一段来自num数组里的元素
vectCpy.insert(vectCpy.end(),vect.begin(),vect.end());//在vectCpy后加入一段来自迭代器对间的元素

  需要注意的是,添加元素可能会导致某些或全部迭代器失效,假设所有迭代器失效是最安全的做法。不要存储end操作返回的迭代器,为了避免存储end迭代器,可以在每次做完插入运算重新计算end迭代器值。

关键概念:容器元素都是副本在容器中添加元素时,系统是将元素值复制到容器里。类似的,使用一段元素初始化新容器时,新容器存放的事原始元素的副本。本复制的原始值与新容器中的元素各不相干,此后,容器内元素值发生变化时,被复制的原值不会受到影响,反之亦然。

容器的比较:

  比较的容器必须具有相同的容器类型,而且其元素类型也必须相同。容器的比较式基于容器内元素的比较。两个容器具有相同的长度而且所有的元素都相等,那么这两个容器就相等。如果两个容器长度不相等,但较短的容器中所有元素都等于较长容器中对应的元素,则称较短的容器小于另一个容器。如果两个容器都是对方的初始子序列,则它们的比较结果取决于所比较的第一个不相等的元素。

复制代码 代码如下:

vector<int> vect;
vect.push_back(1);
vect.push_back(2);
vect.push_back(3);
vector<int> vectCpy(vect);
if(vectCpy==vect) cout<<"Equal"<<endl;
else cout<<"Not Equal"<<endl;

容器大小的操作:

  容器类型提供resize函数来改变容器所包含的元素个数。如果当前的容器长度大于新的长度值,则该容器后部的元素会被删除,如果当前的容器长度小于新的长度值,则系统会在该容器后部添加新元素。resize操作可能会使迭代器失效。例子:

复制代码 代码如下:

list<int> ilist(10,2);//10个元素容器,初始值均为2
ilist.resize(15);//在原有基础上,再后面添加5个元素,初始值为0
ilist.resize(25,-1);//在上行的基础上,再后面再添加10个元素,值为-1
ilist.resize(5);//在ilist的后部删除20个元素

访问元素:

  如果容器非空,那么容器类型的front和back成员将返回容器内第一个或最后一个元素的引用

复制代码 代码如下:

int &ref=vect.front();//front和back返回容器内第一个或最后一个元素的引用
ref=1000001;//改变引用的元素,vect内元素的值也会改变
cout<<vect[0]<<" "<<vect.at(1)<<endl;//只适用于vector和deque,如果给出的下标无效,则会发生outOfRange的异常

删除元素:

  pop_front和pop_back函数用于删除容器内的第一个和最后一个元素。

  删除一个或者一段元素更通用的方法是用erase操作,有两个版本:删除由一个迭代器指向的单个元素,或删除由一对迭代器标记的一段元素。erase返回一个迭代器,它指向被删除元素或元素段后面的元素。通常,必须在容器中查找要删除的元素后,才使用erase操作。寻找一个指定元素最简单的方法,是使用标准库中的find方法。必须包含头文件algorithm.h

复制代码 代码如下:

#include<algorithm>
list<int>::iterator searchIter= find(mylist.begin(),mylist.end(),1233);
if(searchIter!=mylist.end())//有可能找不到
{
mylist.erase(searchIter);
}

  删除容器内所有元素:mylist.clear()或者mylist.erase(mylist.begin(),mylist.end());

容器的选用:

  vector和deque容器提供了对元素的快速随机访问,但付出的代价是,在容器的任意位置插入或删除元素,比在容器尾部插入和删除元素的开销更大。list类型在任何位置都能快速插入和删除,但付出的代价是元素的随机访问开销较大。其原因就是在内部实现的数据结构中,一个是在内存中顺序地址分批的,而另一个是在类似链表的方式,随机地址分配的,所以导致性质的不同。

时间: 2024-10-01 19:10:36

C++Primer笔记之顺序容器的使用详解_C 语言的相关文章

C++聚合关系类的构造函数的调用顺序详解_C 语言

如图,表示一个聚合关系 下面就用简单的代码来实现 #pragma once class Engine { public: Engine(); ~Engine(); }; Engine.h #include <iostream> #include "Engine.h" using namespace std; Engine::Engine() { cout << "调用构造函数:Engine()" << endl; } Engine

C语言线性表的顺序表示与实现实例详解_C 语言

1.概述 通常来说顺序表是在计算机的内存中以数组的形式保存的线性表,是用一组地址连续的存储单元依次存储数据元素的线性数据结构.线性表采用顺序存储的方式存储就称之为顺序表.顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中. 将表中元素一个接一个的存入一组连续的存储单元中,这种存储结构就是顺序结构. 采用顺序存储结构的线性表简称为" 顺序表".顺序表的存储特点是:只要确定了起始位置,表中任一元素的地址都通过下列公式得到:LOC(ai)=LOC(a1)+(i-1)*L 1≤

C++构造函数初始化顺序详解_C 语言

1.构造函数.析构函数与拷贝构造函数介绍 构造函数 1.构造函数不能有返回值 2.缺省构造函数时,系统将自动调用该缺省构造函数初始化对象,缺省构造函数会将所有数据成员都初始化为零或空 3.创建一个对象时,系统自动调用构造函数 析构函数 1.析构函数没有参数,也没有返回值.不能重载,也就是说,一个类中只可能定义一个析构函数 2.如果一个类中没有定义析构函数,系统也会自动生成一个默认的析构函数,为空函数,什么都不做 3.调用条件:1.在函数体内定义的对象,当函数执行结束时,该对象所在类的析构函数会被

C++ STL容器stack和queue详解_C 语言

stack是一个比较简单的容器,它的使用也很简单,stack是LIFO容器,就是后进先出,最后添加进去的元素,第一个取出来 stack初始化 std::stack<int> first; std::stack<int> second(first); std::stack<int, std;:vector<int>> third; //使用vector初始化stack ### stack常用方法### empty();//判断是否为空 push(Elem e)

APUE笔记之:进程环境详解_C 语言

在main中调用exit(1)和reutrn 1是等价的.内核启动一个进程的唯一的方法是调用exec,用户程序终止进程的唯一方法是显示或者隐式的调用_exit或者EXIT.每个进程都会有一个进程表.进程表是一个全局的指针:environ.extern char **environ可以查看这个环境表.另外,可以通过getenv和putenv来获取修改环境表.写个程序试一下.linux的段:linux正文段从0X08048000单元开始,栈底则从0xC0000000开始 栈是向下生长,对向上生长.这

解析c++中参数对象与局部对象的析构顺序的详解_C 语言

下面是c++的源码: 复制代码 代码如下: class X  {public:   int i;   int j;   ~X() {} };void f(X x) {  X x1;  x.i = 1;  x.j = 2; }int main() {    f(X());} 下面是main函数的汇编码: 复制代码 代码如下: _main    PROC ; 15   : int main() {     push    ebp    mov    ebp, esp    sub    esp, 8

阿里云上的容器技术实践详解

为什么选择阿里云 本文讲的是阿里云上的容器技术实践详解,现在的公有云如雨后春笋,国外如AWS.Azure.Bluemix,国内如BAT.DaoCloud.goodrain,都可以给大家提供丰富的云基础设施和上层服务,那么,为什么选择阿里云呢?主要有三点想法: 我们使用阿里云的服务已经有5年了,从企业级PaaS平台合作开始,再到帮助我们的一些客户逐步迁云,对阿里云的能力还是比较熟悉的. 因为要做的是容器,国外AWS,Azure虽然有,但AWS在中国一直没"正规"数据中心(唯一的一个前几天

spring学习笔记(13)基于Schema配置AOP详解

基于Schema配置入门实例 除了基于@AspectJ注解的形式来实现AOP外,我们还可以在IOC容器中配置.先来看看一个常见的应用场景,在我们的web项目中,我们需要为service层配置事务,传统的做法是在每个业务逻辑方法重复下面配置中: Created with Raphaël 2.1.0程序开始1. 获取DAO层封装好的数据库查询API,如HIbernate中的SessionFactory/Session和mybatis中的xxxMapper2. 开启事务3. 根据入参查询数据库完成相应

Docker 手动配置容器网络实例详解_docker

Docker 手动配置容器网络   docker容器的网络是net命名空间与虚拟设备的结合,容器在启动时会创建一对虚拟接口veth pair,这一对接口分别放到本地和容器中,在本地的veth会被分配类似vethxxxx的名称并被桥接到指定网桥的上(默认为docker0),可以通过brctl show命令查看网桥上挂载的接口,在容器中的veth会从网桥获取一个未使用地址,该veth的名称会被更改为eth0并配置默认路由到vethxxxx,docker允许在启动容器的时候通过--net参数指定不同的