c++笔记-顺序容器

  1. 标准库中提供了一些顺序容器。我们在选择不同的容器时,应考虑:向容器中添加或删除元素的代价;非顺序查找元素的代价。
容器名称性能
vector可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢
deque双端队列,支持快速访问。在头尾插入/删除速度很快
list双向链表,只支持双向顺序访问。在list中任何位置插入或者删除操作都很快
forward_list单项链表。只支持单向访问。在链表任何位置进行插入/删除操作速度都很快
array固定大小数组。支持快速随机访问。不能添加或删除元素
string与vector相似的容器,但专门用于保存字符。随机访问块。在尾部增删较快

string和vector容器保存在连续的内存空间中。因此由元素下标来计算地址是非常块的。但在中间增删元素较慢。
list和forward_list设计为方便在任意位置增删元素,但只能顺序访问元素
2. 在容器选择上,除非有更好的选择,一般选用vector。在设计阶段,考虑需求和空间时间来选择容器。标准库中使用左闭合范围[begin, end),如此,若容器不为空begin会指向范围里的第一个元素。

//iter是通过list<string>定义的一个迭代器类型
list<string>::iterator iter;
//count是通过vector<int>定义的一个difference_type类型
vector<int>::difference_type count;
这些声明语句使用了作用域运算符来说明希望使用的迭代器类型
可以使用auto结合begin和end,其获得的迭代器类型依赖于容器类型。
#Tip#
当不需要写访问时,最好使用cbegin和cend
  1. 容器定义和初始化中,只有顺序容器(不包括array)的构造函数才能接受大小参数。为了创建一个容器来为另一容器的拷贝,两个容器的类型必须匹配。不过当传递迭代器参数
array<int, 42> //类型为:保存42个int的数组
array<string, 10> //类型为:保存10个string的数组
#注意#
使用array时,必须同时指定元素的类型和大小:
array<int, 10>::size_type i;
array<int, 10> ia1;//10个默认初始化的int
array<int, 10> ia2 = {0,1,2,3,4,5,6,7,8,9};//列表初始化
array<int, 10> ia3 = {42};//ia3[0]为43,其他位置为0

#Tip#
虽然不能对内置数组类型进行拷贝或者对象赋值操作(必须使用引用),但是array数组可以
int digs[5] = {0,1,2,3,4};
int cpy[5] = digs;//错误操作
array<int, 5> ds = {0,1,2,3,4};
array<int, 5> cy = ds; //正确操作,只要两个数组类型匹配即合法
  1. assign操作定义在顺序容器(array除外)中,允许从一个不同但相容的类型赋值,或者从一个容器的子序列赋值。例如,可以使用assign将一个vector中的一段char*值,赋予一个list中的string。
list<string> names;
vector<const char*> olds;
names.assign(olds.cbegin(), olds.cend());
  1. swap操作交换两个相同类型的容器的内容。除array外,swap操作不对任何元素进行拷贝、删除或插入操作,因此可以保证在常数时间内完成。
  2. 对于容器所支持的关系运算符,只有当其元素类型也定义了相应的比较运算,才可以使用关系运算符比较两个容器。
  3. 向一个vector、string或者deque出入元素会使所有指向容器的迭代器、引用和指针失效。因为可能会引起整个对象对存储空间的重新分配,并将旧的元素移动到新的空间中。
  4. 在对顺序容器(array除外)的操作中,提供了emplace操作,用于在添加元素时构建容器中的对象
//假设c中的元素类型是Sales_data
//使用三个参数的Sales_data构造函数
c.emplace_back("978-0590353403", 25, 15.99);//正确操作
c.push_back("978-0590353403", 25, 15.99);//错误操作,没有这个三个参数的push_back版本
c.push_back(Sales_data("978-0590353403", 25, 15.99));//正确操作,需先创建对象再添加该对象
  1. 在对快速随机访问的容器中,我们建议使用at来访问
vector<string> svec;
cout << svec[0];//错误语法:svec中没有元素!
cout << svec.at(0);//将抛出一个out_of_range异常
  1. 删除元素方式有多种,但是删除操作不会检查元素是否存在,所以删除之前需确保不会出错
c.pop_back() //删除c中尾元素
c.pop_front() //删除c中首元素
c.erase(p)  //删除迭代器p所指元素
c.erase(b, e)   //删除迭代器b和e之间的元素,返回迭代器e
  1. 调整大小函数resize,不适用于array(固定大小)
c.resize(n) //调整c的大小为n个元素。若n < c.size(),则多出的元素被丢弃。
//若必须添加新元素,对新元素进行初始化值
c.resize(n, t) //调整c的大小为n个元素。新的元素初始化为t
  1. 容器的操作可能使迭代器失效,例如向容器中删除元素的操作。因此,使用使用迭代器(或指向容器元素的引用或指针)时,最好保证每次改变容器的操作之后都正确的重新定位迭代器。
  2. 管理容器大小
shrink_to_fit只适用于vector、string和deque
capacity和reserve只适用于vector和string
c.shrink_to_fit() //将回退不需要用到的空间,也就是将原有capacity的空间缩小到目前使用的size上
c.capacity() //不重新分配空间的话,c能保存多少个元素
c.reserve(n) //分配至少能容纳n个元素的内存空间
在对容器使用以后,capacity总会预留出一些空间
当对容器中元素增长时,只要没有超过预留空间大小,不会为vector重新分配新的空间。
调用shrink_to_fit只是请求,不能保证退还给内存
  1. string的构造,当不是以列表初始化构造string时,一般都会在字符串结尾预留一个空字符结束。
const char *cp = "Hello World!!!";
char noNull[] = {"H", "i"};
string s1(cp);//拷贝cp中的字符直到遇到空字符
string s2(noNull, 2);//从noNull拷贝两个字符,s2 = "Hi"
string s3(noNull);//错误用法,noNull未以空字符结束,导致溢出

string的substr操作,返回一个string,它是原来的一部分或者全部的拷贝
  1. 对string搜索操作,搜索返回的是一个string::size_type值,该类型是一个unsigned类型,因此最好不要用int或者其他带符号类型来保存这些函数的返回值
  2. 除了顺序容器外,标准库还定义了三个顺序容器适配器:stack、queue和priority_queue。容器、迭代器和函数都有适配器。一个容器适配器接收一种已有的容器类型。stack类型定义在stack头文件中,queue和priority_queue定义在queue头文件中
stack<int> stk(dep); //从dep拷贝元素到stk
默认情况下,stack和queue是基于deque实现的,priority_queue是在vector之上实现的。
//在vector上实现的空栈
stack<string, vector<strign>> str_stk;
//str_stk2在vector上实现,初始化时保存svec的拷贝
stack<string, vector<string>> str_stk2(svec);

栈的适配器操作:
pop
push
emplace //与push_back类似,可以创建临时对象来添加元素入栈
top //返回栈顶元素但是不删除

队列适配器操作:
pop
push    //对于queue而言是在末尾添加元素,对于priority_queue而言,在恰当位置添加元素
front   //返回首元素或为元素,但不删除该元素
back    //只适用于queue
top //返回优先级最高的元素,但不删除
emplace

标准库中queue使用先进先出策略,而使用priority_queue允许为元素添加优先级关系,新增元素优先级排在低优先级之前
  1. 每个适配器都定义了两个构造函数,默认构造函数创建一个空的对象;接收一个容器的构造函数拷贝该容器来初始化该适配器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值