C++顺序容器笔记

来源:互联网 发布:淘宝仓库怎么看 编辑:程序博客网 时间:2024/06/06 07:28
题记:
关于容器, C++primer 有详细描述,网上也有各种资料,而我写这篇文章的意义在于:阅读 C++primer 之后的总结、复习以及理解。
概念
容器( container),保存一组给定类型对象的类型。 因为引用不是对象,所以,容器的类型不能是引用。 每个标准库容器类型都是一个模板类型。为了定义容器,我们必须指定保存在容器中元素的类型。除了 array 之外,标准库容器的大小都是可变的。
顺序容器 (sequentail container) ,元素在容器的顺序,和加入容器时的位置相对象,元素通过位置来访问。
关联容器( associative container ),元素通过关键字高效访问。
vector ,顺序容器,可变大小数组, vector 中的元素可以通过下标访问,支持快速随机访问。在尾部插入或者删除元素效率很高,其他位置插入删除元素会导致数组重新分配空间,效率有限。在 vector 添加或者删除元素,如果导致内存重新分配,那么整个迭代器都会失效,否则,修改点之后的迭代器失效。
deque ,顺序容器,双端队列。元素可通过下标访问,支持快速随机访问,支持在头尾快速插入删除元素。 deque 在各方面都和 vector类似,唯一的差别是,支持在容器的头尾快速删除插入元素,而且两端的插入删除操作不会导致重新分配空间。
list ,双向链表,只支持双向顺序访问。从一个给定元素开始,为了访问另一个元素,需要遍历链表。可在任何位置高效的插入删除元素而不使迭代器失效(除了删除的元素之外)。
forward_list ,单向链表。 C++11新加入,元素只能顺序访问。其设计目标是达到于最好的手写单链表有相当的性能。因此, forward_list 没有size 操作。
array ,固定大小数组,创建时必须给定大小。支持快速随机访问,不能添加或者删除元素。
string ,与vector 相似的容器,但专门用于保存字符。
在顺序容器中,除了固定大小的 array 之外,其他容器都提供高效的、灵活的内存管理。可以添加、删除、扩张或者缩小容器大小。容器保存元素的策略(内部数据结构),对容器的操作效率有固定的重大的影响。某些情况下,策略还决定是否支持容器特定操作。
例如, vector string 都是将元素保存在连续的内存空间,可以用下标快速访问,但是要在中间插入或者删除元素,就会破坏空间的连续性,导致移动修改点之后的元素或者重新分配空间来保持空间连续性,所以,插入删除效率就不高。相对的, list 是以链表的形式保存元素的,所以,插入或者删除元素都很快,只需重新维护插入删除位置的链表即可,但是不支持随机访问,需遍历链表。而且,相对于 vector list 的内存开销会很大。而 deque 是一个更为复杂的数据结构,详情可参考 http://www.cnblogs.com/zhangchaoyang/articles/2277209.html 。总之,容器的内部数据结构决定其访问能力、效率。
迭代器
迭代器是一种类型,用于访问容器中的元素或者再元素之间移动。迭代器的实现可能是指针、也可能是类,参考 http://blog.csdn.net/yxysdcl/article/details/5567460
标准容器迭代器的运算符: iter->mem (解引用)、 *iter(返回元素引用)、 ++ --  ==、! = ,其中forward_list 不支持 运算。除此之外, vector string  deque array 的迭代器还支持以下运算: +n -n  +=n -=n iter1-iter2  > < <=  >=
迭代器范围:一个迭代器范围由一对迭代器表示,分别指向同一容器不同元素,为左闭合区间。
反向迭代器:按逆序寻址元素的迭代器,不支持 forward_list 
begin() 返回容器第一个元素的迭代器; rbegin() 返回反向迭代的第一个元素; cbegin() 返回const 类型的迭代器。其中不以 c 开头的begin  rbegin是重载过的,有两个版本,分别返回 iterator const_iterator 类型。对应的 end() rend()  cend() crend() 类似。以c 开头的迭代器是 C++11 新引入的,结合 auto使用比较方便。另外, forward_list 还有一个首前迭代器,返回第一个元素之前的迭代去, before_begin(),cbefore_begin() 
定义和初始化

其中,表格中第二个构造函数 C c1(c2) c1  c2必须有相同的类型,否则报错。其他函数满足类型的隐式转换也可以。使用大括号的第四个和第五个为列表初始化,显示的指定每个元素的值,同时,隐式的指定了容器的大小( array )除外。特别的 vector<string> v{10 “hi”}定义 10 个值为hi 的元素的容器, vector<string> v{10} 定义10 个值为空的元素的容器。
赋值和 swap

赋值运算符要求左边和右边的运算对象具有完全相同的类型。 assign 允许我们从一个不同但相容的类型赋值,或者从容器的子序列赋值。例如,可以使用 assign 讲一个vector 中的一段 char* 值赋予一个list 中的 string
添加元素

array 是固定数组。 forward_list是单链表,故此,不支持 push_back emplace_back 。同理 vector string 是动态数组,不支持在头部插入数据。
insert emplace 在容器的特定位置插入元素,该位置由第一个参数 p (迭代器)指定,在 p之前插入后续参数指定的元素,返回插入的第一个元素的迭代器。
C++11 标准引入了三个 emplace成员,这些操作直接构造元素,例如:


访问元素
迭代器解引用、 back front  at [] 。访问成员函数返回的是引用,可以直接用来改变元素的值。但是,在使用 auto 定义变量时,会忽略引用和顶层 const 类型,需自己添加。
删除元素

特殊的 forward_list操作

ps:

1、 容器类型不能是引用,因为引用并不是类型。

2、 接受容器大小的构造函数seq(n),其类型是explicit的,不能对类型隐式转换。如

vector<string> s("ee"); //error无构造函数可以接受源类型

当使用该构造函数时,需使用元素的默认构造函数取创建元素,所以,必须保证元素有默认构造函数。如:

// 假定Nodefault是一个没有默认构造函数的类型

         vector<Nodefault>v1(10, init);  //ok提供了元素的初值

vector<Nodefault>v1(10);        // error 没有初值,无法初始化

3、 array不支持普通的容器构造函数,元素被默认初始化。如

array<int, 10> i;   //默认初始化为0

array<string, 2> ss = {"123" };  //第一个元素为123,后一个元素为空

0 0
原创粉丝点击