C++ primer 第9章 顺序容器

文章目录

  • 顺序容器类型
    • 确定使用哪种顺序容器
  • 容器库概览
    • 容器操作
    • 迭代器
      • 迭代器支持的所有操作
      • 迭代器支持的所有运算
      • 迭代器范围
        • 对构成范围的迭代器的要求
        • 标准库迭代器范围左闭右开的三种性质
    • 容器定义和初始化
      • 将一个新容器创建为另一个容器的拷贝
        • 将array拷贝到vector中的代码
      • 与顺序容器大小相关的构造函数
      • 标准库array具有固定大小
    • 赋值和swap
      • 测试swap的代码
    • 关系运算符
  • 顺序容器的特有操作
    • 向顺序容器添加元素
      • 容器元素是拷贝
      • 在容器中特定位置添加元素:insert
      • emplace操作
    • 访问元素
      • 访问成员函数返回的是引用
    • 删除元素
    • 特殊的forward_list操作
    • 改变容器大小
    • 容器操作可能使迭代器失效
  • vector对象是如何增长的
    • capacity和size
  • 额外的string操作
    • 构造string的其他方法
    • substr操作
    • 从一个vector \

顺序容器类型

在这里插入图片描述
string和vector将元素保存在连续的内存空间中,因此支持快速随机访问,但是在这两种容器的中间位置添加或删除元素会非常耗时,因为需要移动插入/ 删除位置之后的所有元素,来保持连续存储。而且添加一个元素有时可能还需要分配额外的存储空间,这种情况下,每个元素都必须移动到新的存储空间中。
list和forward_list两个容器添加和删除操作快速,但不支持元素的随机访问,为了访问一个元素只能遍历整个容器,其存储的内存空间不连续。
deque支持快速随机访问,中间位置添加或删除元素非常耗时,但是在deque的两端添加或删除元素很快。

确定使用哪种顺序容器

通常,使用vector是最好的选择,除非你有很好的理由选择其他容器。
在这里插入图片描述

容器库概览

一般来说,每个容器都定义在一个头文件中,文件名与类型名相同,即deque定义在头文件deque中,list定义在头文件list中,以此类推。容器均定义为模板类,例如对vector,我们必须提供额外信息来生成特定的容器类型。对大多数,但不是所有容器,我们还需要额外提供元素类型信息:

list<Sales_data> 保存Sales_data对象的list
deque<double> 保存double的deque

顺序容器几乎可以保存任意类型的元素。特别是,我们可以定义一个容器,其元素的类型是另一个容器。这种容器的定义与任何其他容器类型完全一样:

vector<vector<string>> lines; 此处lines是一个vector,其元素类型是string的vector

容器操作

在这里插入图片描述
在这里插入图片描述

迭代器

迭代器支持的所有操作

forward_list迭代器不支持递减运算符
在这里插入图片描述

迭代器支持的所有运算

这些运算只适用于string、vector、deque和array的迭代器,我们不能将它们用于其他任何容器类型的迭代器。

例如,list的迭代器不支持<运算,只支持递增、递减、==以及!=运算,原因在于list是将元素以链表方式存储,在内存中不连续,两个指针的大小关系与它们指向的元素的前后关系并不一定是吻合的,实现<运算将会非常困难和低效。
在这里插入图片描述

迭代器范围

一个迭代器范围由一对迭代器表示,两个迭代器分别指向同一个容器中的元素或者是尾元素之后的位置。这两个迭代器通常被称为begin和end

对构成范围的迭代器的要求

如果满足如下条件,两个迭代器begin和end构成一个迭代器范围:
它们指向同一个容器中的元素,或者是容器最后一个元素之后的位置,且我们可以通过反复递增begin来到达end。换句话说,end不在begin之前。

标准库迭代器范围左闭右开的三种性质

假定begin和end构成一个合法的迭代器范围,则

  • 如果begin与end相等,则范围为空
  • 如果begin与end不相等,则范围至少包含一个元素,且begin指向该范围中的第一个元素
  • 我们可以对begin递增若干次,使得begin==end

容器定义和初始化

每个容器类型都定义了一个默认构造函数。除array之外,其他容器的默认构造函数都会创建一个指定类型的空容器,且都可以接受指定容器大小和元素初始值的参数。
在这里插入图片描述

将一个新容器创建为另一个容器的拷贝

为了创建一个容器为另一个容器的拷贝,两个容器的类型及其元素类型必须匹配。不过,当传递迭代器参数来拷贝一个范围时,就不要求容器类型是相同的了,而且新容器和原容器中的元素类型也可以不同,只要能将要拷贝的元素转换为要初始化的容器的元素类型即可。
在这里插入图片描述

将array拷贝到vector中的代码

int ia[] = { 0,1,1,2,3,5,8,13,21,55,89 };
vector<int>vect;
vect.assign(ia,ia+11);

与顺序容器大小相关的构造函数

如果元素类型是内置类型或者是具有默认构造函数的类类型,可以只为构造函数提供一个容器大小参数。如果元素类型没有默认构造函数,除了大小参数外,还必须指定一个显式的元素初始值。
只有顺序容器的构造函数才接受大小参数,关联容器并不支持。

标准库array具有固定大小

与内置数组一样,标准库array的大小也是类型的一部分。当定义一个array时,除了指定元素类型,还要指定容器大小,例如array<int,42>
与其他容器不同,一个默认构造的array是非空的:它包含了与其大小一样多的元素。这些元素都被默认初始化。如果我们对array进行列表初始化,则初始值的数目必须等于或小于array的大小。如果初始值数目小于array的大小,则它们被用来初始化array中靠前的元素,所有剩余元素都会进行值初始化。在这两种情况下,如果元素类型是一个类类型,那么该类必须有一个默认构造函数,以使值初始化能够进行。

我们不能对内置数组类型进行拷贝或对象赋值操作,但array并无此限制:
在这里插入图片描述

赋值和swap

与内置数组不同,标准库array类型允许赋值,赋值后左右两边的运算对象需具有相同的类型:

array<int, 10>a1 = {0,1,2,3,4,5,6,7,8,9};
array<int, 10>a2 = { 0 };
a1 = a2;//此时a1中的元素为10个0

在这里插入图片描述
除array外,swap不对任何元素进行拷贝、删除或插入操作,因此可以保证在常数时间内完成。
除string外, 指向容器的迭代器、引用和指针在swap操作之后都不会失效,它们仍指向swap操作之前所指向的那些元素,但是在swap之后,这些元素已经属于不同的容器了,详情可见对vector进行测试的代码。与其他容器不同,swap两个array会真正交换它们的元素,因此,对于array,在swap操作之后,指针、引用和迭代器所绑定的元素保持不变,但元素值已经与另一个array中对应元素的值进行了交换,详情可见对array进行测试的代码。

测试swap的代码

对array进行测试的代码

int main() {array<int, 10>a1 = {1};array<int, 10>a2 = {0};auto beg1 = a1.begin();auto beg2 = a2.begin();cout << "swap之前:" << endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a : a2) {cout << a << " ";}cout << endl;cout << "a1.begin:"<< *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;swap(a1,a2);cout << "swap之后:"<<endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a:a2) {cout << a << " ";}cout << endl;cout << "a1.begin:" << *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;system("pause");return 0;
}

测试结果:

swap之前:
a1元素:1 0 0 0 0 0 0 0 0 0
a2元素:0 0 0 0 0 0 0 0 0 0
a1.begin:1
a2.begin:0
swap之后:
a1元素:0 0 0 0 0 0 0 0 0 0
a2元素:1 0 0 0 0 0 0 0 0 0
a1.begin:0
a2.begin:1

对vector进行测试的代码:

int main() {vector<int>a1 = {1};vector<int>a2 = {0};auto beg1 = a1.begin();auto beg2 = a2.begin();cout << "swap之前:" << endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a : a2) {cout << a << " ";}cout << endl;cout << "a1.begin:"<< *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;swap(a1,a2);cout << "swap之后:"<<endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a:a2) {cout << a << " ";}cout << endl;cout << "a1.begin:" << *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;system("pause");return 0;
}

测试结果:

swap之前:
a1元素:1
a2元素:0
a1.begin:1
a2.begin:0
swap之后:
a1元素:0
a2元素:1
a1.begin:1
a2.begin:0

关系运算符

每个容器都支持相等运算符(==和 !=),除了无序关联容器外的所有容器都支持关系运算符(>,>=,<,<=),关系运算符左右两边的运算对象必须是相同类型的容器,且必须保存相同类型的元素。
比较两个容器实际上是进行元素的逐对比较:

  • 如果两个容器具有相同大小且所有元素都两两对应相等,则这两个容器相等;否则两个容器不等
  • 如果两个容器大小不同,但较小容器中每个元素都等于较大容器中的对应元素,则较小容器小于较大容器
  • 如果两个容器都不是另一个容器的前缀子序列,则它们的比较结果取决于第一个不相等的元素的比较结果

顺序容器的特有操作

向顺序容器添加元素

除array外,所有标准库容器都提供灵活的内存管理,在运行时可以动态添加或删除元素来改变容器大小。
在这里插入图片描述

容器元素是拷贝

当我们用一个对象来初始化容器时,或将一个对象插入到容器中时,实际上放入到容器中的是对象值的一个拷贝,而不是对象本身。容器中的元素与提供值的对象之间没有任何关联,随后对容器中元素的任何改变都不会影响到原始对象,反之亦然。

在容器中特定位置添加元素:insert

在新标准下,接受元素个数或范围的insert版本返回指向第一个新加入元素的迭代器,如果范围为空,不插入任何元素,insert操作会将第一个参数返回。
通过使用insert的返回值,可以在容器中一个特定位置反复插入元素。

s.iinsert(iter,"hello")"hello"添加到iter之前的位置
s.iinsert(iter,10,"hello")    将10个"hello"添加到iter之前的位置
s.insert(s.begin(),s2.begin(),s2.end())  将指定范围中的元素插入到给定迭代器位置之前
s.insert(s.begin(),{"the","haha","heihei"}) 将初始化列表中的元素插入到给定位置之前
s.insert(s.begin(),s.begin(),s.end())  此句错误,拷贝的范围不能指向与目的位置相同的容器

emplace操作

在这里插入图片描述

访问元素

在这里插入图片描述

访问成员函数返回的是引用

在容器中访问元素的成员函数(即,front、back、下标和at)返回的都是引用。如果容器是一个const对象,则返回值是const的引用。如果容器不是const的,则返回值是普通引用,我们可以用来改变元素的值:
在这里插入图片描述

删除元素

在这里插入图片描述

特殊的forward_list操作

在这里插入图片描述

改变容器大小

在这里插入图片描述
示例代码如下:
在这里插入图片描述

容器操作可能使迭代器失效

向容器中添加元素和从容器中删除元素的操作可能会使指向容器元素的指针、引用或迭代器失效。一个失效的指针、引用或迭代器将不再表示任何元素。使用失效的指针、引用或迭代器是一种严重的程序设计错误,很可能会引起与使用未初始化指针一样的问题。
在这里插入图片描述
如果在一个循环中插入/删除deque、string或vector中的元素,不要缓存end返回的迭代器,必须在每次操作后重新调用end(),而不能在循环开始前保存它返回的迭代器。

vector对象是如何增长的

在这里插入图片描述
reserve并不改变容器中元素的数量,它仅影响vector预先分配多大的内存空间。

capacity和size

容器的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。

额外的string操作

除了顺序容器共同的操作之外,string类型还提供了一些额外的操作,这些操作中的大部分要么是提供string类和c风格字符数组之间的相互转换,要么是增加了运行我们用下标代替迭代器的版本。

构造string的其他方法

在这里插入图片描述
代码示例:
在这里插入图片描述

substr操作

在这里插入图片描述
在这里插入图片描述

从一个vector <char> 初始化一个string

vector提供了一个data成员函数,返回其内存空间的首地址

vector<char>vi{ 'a','b' ,'c','d'};
string s(vi.begin(),vi.end());
string s2(vi.data(),vi.size());

改变string的其他方法

在这里插入图片描述
在这里插入图片描述

string的下标版本的insert和erase版本

string类型支持顺序容器的赋值运算符以及assign、insert和erase操作,除此之外,它还定义了下标版本的insert和erase版本:

	string s="0123456789";s.insert(5, 3, 'A'); //此时s是01234AAA56789,即在s[5]之前插入3个‘A’string s1 = "0123456789";s1.erase(5, 3);//此时s1是0123489,即删除s[5]之后的3个元素,包括s[5]

string的c风格字符数组版本的insert和erase版本

	const char *cp = "0123456789";string s;s.assign(cp,5);  //s=="01234"s.insert(s.size(),cp+7);s=="01234789"
	string s = "some string";string s2 = "some other string ";s.insert(0,s2);//s=="some other string some string"// 在s[0]之前插入s2中s2[0]开始的s2.size()个字符s.insert(0,s2,0,s2.size());//s=="some other string some other string some string"

append和replace函数

string s="some ";
s.append("things"); //s=="some things"
s.replace(5,3,"hhhh");//s=="some hhhhngs"即从s[5]开始将3个元素,替换为“hhhh”

string搜索操作

string搜索操作,每个操作都返回一个string::size_type值,表示匹配位置的下标。如果搜索失败,则返回一个名为string::npos的static成员。
在这里插入图片描述
在这里插入图片描述

string find

find查找参数指定的字符串,若找到,则返回第一个匹配位置的下标,否则返回npos

string name("AnnaBelleAnnaBelle");
auto pos1=name.find("Anna");//pos1==0
auto pos2 = name.find("Anna",1);//pos2==9 此处是从name[1]处开始查找"Anna",返回第一个匹配位置的下标

string find_first_of

	string numbers("0123456789");string name("n1inin4n");auto pos1 = name.find_first_of(numbers,2);//pos1==6auto pos1 = name.find_first_of(numbers);//pos1==1

string compare函数

根据s是等于、大于还是小于参数指定的字符串,s.compare返回0、正数或负数。
在这里插入图片描述

数值转换

	int i = 42;string s = to_string(i);//将整数i转换为字符“42”double num = stod(s);// 将字符“42”转换为浮点数42
	s = "00110011";int num = stoi(s,0,2);// 将s转换为二进制,num==51

在这里插入图片描述

容器适配器

除了顺序容器外,标准库还定义了三个顺序容器适配器:stack、queue和priority_queue。
默认情况下,stack和queue是基于deque实现的,priority_queue是在vector之上实现的。
适配器是标准库中的一个通用概念,容器、迭代器和函数都有适配器。本质上,一个适配器是一种机制,能使某种事物的行为看起来像另外一种事物一样。一个容器适配器接受一种已有的容器类型,使其行为看起来像一种不同的类型。

所有容器适配器都支持的操作和类型

在这里插入图片描述

栈适配器

stack定义在stack头文件中,先进后出
在这里插入图片描述

队列适配器

queue和priority_queue定义在queue头文件中。
queue,先进先出
priority_queue,允许我们为队列中的元素建立优先级,新加入的元素会排在所有优先级比它低的已有元素之前。默认情况下,标准库在元素类型上使用<运算符来确定相对优先级。
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

牛客网C++面经 容器和算法

原文网址 参考网址 C语言中文网 请你来说一下map和set有什么区别&#xff0c;分别又是怎么实现的&#xff1f; map和set都是C的关联容器&#xff0c;其底层实现都是红黑树&#xff08;RB-Tree&#xff09;。由于 map 和set所开放的各种操作接口&#xff0c;RB-tree 也都提供…

C++ primer 第10章 泛型算法

文章目录概述findcount初识泛型算法只读算法只读算法accumulate只读算法equal写容器元素的算法算法fill算法fill_nback_inserter算法copy算法replace replace_copy重排容器元素的算法sortuniqueunique_copy定制操作向算法传递函数谓词算法stable_sort算法partitionlambda表达式…

C语言常用字符串函数

概括 代码 #include<stdlib.h> #include<stdio.h> #include<string.h> int main() {//常用字符串函数char a[]"abcSDFbnm";char b[]"SD";printf("a的字符串长度:%d\n",strlen(a));printf("b的字符串长度:%d\n",str…

C++ primer 第11章 关联容器

文章目录使用关联容器map示例关联容器概述定义关联容器关联容器值初始化multimap和multiset关键字类型的要求pair类型pair上的操作关联容器操作关联容器额外的类型别名关联容器迭代器map迭代器set迭代器关联容器和算法添加元素向map添加元素检测insert的返回值使用insert代替下…

C++ primer 第12章 动态内存

文章目录前言动态内存与智能指针shared_ptr类shared_ptr和unique_ptr都支持的操作shared_ptr独有的操作make_shared 函数shared_ptr的拷贝和赋值shared_ptr自动销毁所管理的对象shared_ptr还会自动释放相关联的内存程序使用动态内存出于以下原因直接管理内存使用new动态分配和初…

C语言顺序查找二分查找

介绍 顺序查找 按照顺序一个个查找 #include<stdio.h> //顺序查找 int search(int arr[],int len,int aim) {int i;for(i0;i<len;i){if(arr[i]aim){return i;//返回下标 }}return -1;//表示未查询到} int main() {int arr[]{13,355,256,65,234,-1,35,-6,-3,-4,0};…

C++ primer 第12章 12.3 使用标准库:文本查询程序

文章目录使用标准库&#xff1a;文本查询程序文本查询程序设计数据结构在类之间共享数据自己的文本查询程序书中的文本查询程序使用标准库&#xff1a;文本查询程序 我们将实现一个简单的文本查询程序&#xff0c;作为标准库相关内容学习的总结。 我们的程序允许用户在一个给…

C语言二维数组 int arr[2][3]

基础使用 先遍历行再遍历列 #include<stdio.h> //二维数组的基本使用 int main() {//二维数组的初始化int arr1[2][2]{{2,2},{0,0}};int arr2[2][3]{2,2,2,8,8,8};int arr3[6][9];int i,j;for(i0;i<6;i){for(j0;j<9;j){arr3[i][j]1;}}arr3[2][5]0;//打印printf(&…

C++ primer 第13章 拷贝控制

文章目录前言拷贝、赋值与销毁拷贝构造函数合成拷贝构造函数拷贝初始化和直接初始化拷贝初始化的发生&#xff1a;参数和返回值拷贝初始化的限制拷贝赋值运算符重载赋值运算符合成拷贝赋值运算符析构函数析构函数完成的工作什么时候会调用析构函数合成析构函数代码片段调用几次…

C语言 指针自增自减加减运算 p++ p+i

介绍 自增自减代码 #include<stdio.h> #include<string.h> //指针自增--short void increase(short *arr,int len) {int i;arr&arr[0];for(i0;i<len;i){printf("arr[%d]%d,address%p\n",i,*arr,arr);arr;} }//指针自减--char void decrease(char…

C++ 编译与底层

原文链接 编译与底层请你来说一下一个C源文件从文本到可执行文件经历的过程&#xff1f; 对于C源文件&#xff0c;从文本到可执行文件一般需要四个过程&#xff1a;预处理阶段&#xff1a;对源代码文件中文件包含关系&#xff08;头文件&#xff09;、预编译语句&#xff08;…

C语言 指针数组-字符指针数组整型指针数组 char*s[3] int*a[5] 数组指针int(*p)[4]

基本介绍 1.指针数组:由n个指向整型元素的指针而组成,里面存放指针 Int *ptr[3]; 2.地址: ptr[i]:元素地址 &ptr[i]:指针地址 图示 代码: 内存布局: 代码 #include<stdio.h> #include<string.h> //指针数组--int void pointer(int *arr,int len) {int …

C语言 多重指针--整型字符字符串 int**pp

介绍 多重指针:一个指针指向另一个指针 离值越近的指针级别越大:一级 内存布局 代码 图示: 多重指针–整型 #include<stdio.h> #include<string.h> //多重指针--整型//二级指针 void two() {printf("二级指针:\n");int a896;int *p&a,**pp&…

C++ primer 第13章 拷贝控制

文章目录前言拷贝、赋值与销毁拷贝构造函数合成拷贝构造函数拷贝初始化和直接初始化拷贝初始化的发生&#xff1a;参数和返回值拷贝初始化的限制拷贝赋值运算符重载赋值运算符合成拷贝赋值运算符析构函数析构函数完成的工作什么时候会调用析构函数合成析构函数代码片段调用几次…

牛客网C++面经 C++11

请问C11有哪些新特性&#xff1f; auto关键字&#xff1a;编译器可以根据初始值自动推导出类型。但是不能用于函数传参以及数组类型的推导nullptr关键字&#xff1a;nullptr是一种特殊类型的字面值&#xff0c;它可以被转换成任意其它的指针类型&#xff1b;而NULL一般被宏定义…

C语言 返回指针的函数--指针函数 int* max(int a)

定义 strlong示例代码 代码1: #include<stdio.h> #include<string.h> //返回指针的函数//比较两个字符串,返回更长的字符串 char *strlong(char* a,char* b) {char *p1&a[0];char *p2&b[0];while(true){if(*p1\0){return b;}else if(*p2\0){return a;}p1…

第2、3讲 图像的存储格式

本图像处理系列笔记是基于B站杨淑莹老师的课程进行学习整理的。 文章目录黑白图像8位灰度索引图像8位伪彩色索引图像24位真彩色图像图像文件格式BMP文件存储格式BMP文件头位图信息头颜色表位图信息——BITMAPINFO结构BMP位图文件汇总按照颜色深度分类&#xff0c;常用图像文件&…

Ubuntu18.04.4 环境下对属性加密算法CP-ABE环境搭建

注意事项 cpabe依赖pbc&#xff0c;pbc依赖gmp&#xff0c;gmp依赖M4、bison、flex如果权限不够 &#xff0c;命令的前面加上sudo &#xff0c;不要直接使用root用户进行操作&#xff0c;其带来的隐患有很多 第一步 配置简单的环境 简单环境 包括gcc、g、make、cmake、openss…

C语言 函数指针 int(*ptr)(int,int)

基本介绍 函数指针:指向函数的指针 与数组类似 定义 Int(*pmax)(int ,int)max; Int(*pmax)(int x,int y)max;//形参名称不重要 函数返回类型(*指针)(形参类型)函数名称; 具体案例 代码: *pmax取到函数本身 调用函数指针方式: (*pmax)(x,y); pmax(x,y);//与java中调用函数一…

C++ primer 第14章 操作重载与类型转换

文章目录基本概念直接调用一个重载的运算符函数某些运算符不应该被重载使用与内置类型一致的含义选择作为成员或者非成员输入和输出运算符重载输出运算符<<输出运算符尽量减少格式化操作输入输出运算符必须是非成员函数重载输入运算符>>算术和关系运算符相等运算符…