简介:
顺序容器:vector(矢量) , list(链表) , deque(双端队列)
关联容器:map , set ,multimap , multiset
区别:顺序与关联的本质区别在于关联容器通过键存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。
一. 顺序容器
1.构造函数
所有的容器都定义了默认构造函数,也是容器最常用的构造函数,在大我数程序中,使用默认构造能达到最佳运行时性能,并使容器更容易使用
vector<int> ve1; 默认构造函数
vector<int> ve2(ve1); ve2与ve1必须具有相同的元素类型
vector<int> ve3(begin,end);创建ve3,其元素是从迭代器begin到end之间的元素
vector<int> ve4(n ,value);用n个值为value的元素创建容器-----只适用于顺序容器
vector<int> ve5(n); 用n个值为默认初始化的元素创建容器-----只适用于顺序容器
接爱容器大小为形参的构造函数只适用于顺序容器,关联容器不支持!!
2.容器内元素的类型约束
* 元素类型必须支持赋值运算
* 元素类型的对象必须可以复制
容器的容器:如 vector< vector<string> >必须用空格隔开相邻的>符号,否则系统会认为是 >> 右移符号,导致编译错误。
3.迭代器和迭代器范围
迭代器是由容器本身定义的一种检查容器内元素并遍历元素的数据类型。
迭代器为所有标准库容器类型所提供的运算:
*iter 返回迭代器iter所指向的元素的引用 iter->mem 对iter进行解引用,获取指定元素中名为mem的成员,相当于(*iter).mem; ++iter,iter++,--iter,iter-- 自增,自减操作 iter1 == iter2 比较两个迭代器是否相等
|
iter+n ; iter-n ; iter1+=iter2 ;iter1-iter2 ; >,>=,<,<=
迭代器范围:这个概念是c++标准库的基础
迭代器范围是一个左闭合区间【begin,end)end是指向最后一个元素的下一个位置
关于迭代器失效的容器操作在容器操作后详细讨论!
4.添加操作
添加,删除,设置容器大小,(如果有的话)获取第一个和最后一个元素
begin()与end():返回的是容器第一个元素和最后一个元素的下一个位置的迭代器。
添加操作: push_back(value) 在容器的尾部添加值为value的元素,返回值为void push_pront(value) 在容器的前端添加值为value的元素,返加值为void---只适用于list和deque容器 insert(iter,value) 在iter指向的元素前插入值为value的元素,返回指向新添加的元素的迭代器 insert(iter,n,value) 在迭代器iter指向的元素前插入n个值为value的元素,返回void inset(iter,begin,end) 在迭代器iter指向的元素前插入由迭代器begin,end标记的范围内的元素,返回void
|
5.删除元素
erase(p) 删除迭代器p所指向的元素,返回指向被删除元素后面的元素的迭代器 erase(b,e) 删除迭代器b,e之间的元素,“返回指向被删除元素段的最后一个元素的迭代器?” clear() 清空容器,返回void pop_back 删除最后一个元素,返回void pop_front 删除第一个元素,返回void---只适合list和deque |
erase操作也不会检查它的参数,要靠程序员确保参数的迭代器有效,一般通过find()算法,找到要删除的迭代器
6.容器大小的操作
size() 返回容器中的元素个数,类型容器::size_type; max_size() 返回容器最大可以容纳元素的大小 empty() 空则返回true resize(n) 调整容器的大小为n resize(n,value) 调整容器的大小为n,并添加元素的值都为value |
7.访问元素
back() 返回容器最后一个元素的引用 front() 返回第一个元素的引用 [n] 下标只适合 vector和 deque |
8.赋值与交换内容。
C1 = C2 赋值:删除容器C1的所有元素,然后将C2的元素复制给C1,C1,C2类型要相同 assign(b,e) 先删除所有元素,再将迭代器b,e范围内的所有元素复制到容器中,b,e必须是其它容器的迭代器 assign(n,t) 将容器重新设置为存储n个值为t的元素 C1.swap(C2) 交换内容,互相交换 |
赋值和assign操作使容器所有的迭代器失效,而swap操作则不会使迭代器失效!
使用swap操作以节省删除元素的成本!
9.两个内存分配成员
capacity() 容器的容量
reserve() 重新分配容量
10.迭代器失效
1.任何 insert或 push操作都可能导致迭代器失效,当编写循环将元素插入到vector,deque容器中时,程序必须确保迭代器在每次循环后都得到更新。
2.每次做完添加或删除操作后,vecter或deque容器的end()返回的迭代器是会发生改变的,所以要避免存储end操作返回的迭代器,如:
Vector<int> vec::iterator first = vec.begin(),last =vec.end();
While(first != last)
{/*“添加或删除操作”*/}
3.对于所有的容器类型,如果resize操作压缩了容器,则指向已删除的元素的迭代器失效!
当改变的长度小于原来的长度,该容器后部的元素会被删除。
4.赋值(=),assign操作都将使容器所有的迭代器失效
11.容器的选用
vector ,list , deque三种容器分析:
vector:动态数组,连续的内存区域,支持对元素的快速随机访问,但在容器任意位置添加和删除元素的开销较大,因为其它位置的元素需要移动
list:链表,不连续的内存区域,允许向前和向后遍历元素。在任何位置都可以高效的添加和删除一个元素,其它元素不需要移动,
但付出的代价是不支持随机访问,访问某个元素需要遍历所涉及的其它元素。
deque:同进提供了以上两种容器的一些性质
1. 与vector一样,在中间位置插入和删除元素效率比较低
2. 不同于vector的是,deque容器在首部可以实现和尾部一样的高效
3. 支持元素的随机访问
4. 在首部和尾部插入元素不会使任何迭代器失效,而在首部和尾部删除元素则只会使指向被删除元素的迭代器失效。
从元素访问角度选择:
通常来说,除非找到选择使用其他容器的更好理由,否则vector将是最佳选择。
原因:虽然vector和deque都可以高效的支持随机访问,但vector因为是连续内存区域,每次访问都是距离共起点的因定偏移,因此其访问非常有效率。
容器选择总结:
1. 要求随机访问,应使用vector或deque,vector更优
2. 如果必须在容器的中间位置插入或删除元素,应采用list容器
3. 如果不是必须在容器的中间位置插入或删除,而是在首部或尾部,应采用deque容器
4. 如果只需在读取时在容器中间位置插入元素,然后需要随机访问元素,则可考虑:
先用list容器存储,再接将list容器复制到一个vector容器中
下章笔记:关联容器