const迭代器和const_iterator的区别:
前者不可以改变指向但可以改变所指地址的值
后者可以改变指向但不能改变所指地址的值;
顺序容器
vector | 可变大小数组,支持随机访问,在尾部之外的位置插入和删除可能很慢 |
---|---|
deque | 双端队列,支持随机快速访问。在头尾位置插入和删除很快 |
list | 双向链表,只支持双向顺序访问。在任何位置插入和删除都很快 |
forward_list | 单向链表,只支持单向顺序访问,在任何位置插入和删除都很快 |
array | 固定大小数组,支持快速随机访问,不能添加和删除元素 |
string | 与vector相似的,但专门用于保存字符,在尾部插入和删除很快 |
string和vector将元素保存在连续的内存空间中,但每一次添加和删除操作都需要移动元素。非常耗时。
list和foward_list中任何位置的删除和插入操作都十分快速,但不支持元素的随机访问。
deque与string和vector类似,支持快速的随机访问,在中间位置插入和删除代价可能很高,在两端则很快
forward_list不支持size操作
容器操作:详见其api文档和数据结构
c.cbegin()和c.cend()返回const_iterator
size_type 无符号整数类型,足够保存此种容器的最大可能容器的大小
c.insert(args) 将args中的元素拷贝进c;此处会调用拷贝构造
//C++11新特性之emplace
c.emplace(init) 使用init直接构造c中的一个元素,直接调用构造函数
将一个容器初始化为另一个容器的拷贝
此时,两个容器的类型和元素类型必须严格匹配,不过,当用迭代器来拷贝一个范围的话吗就不要容器类型是是相同的,而且元素类型也不需要相同,只要能将要拷贝的元素转换为初始化容器的元素类型即可。
如果容器的元素类型是内置类型或者具有默认构造函数的类类型,那么可以只为构造函数提供一个容器大小的参数,反之不可!
定义一个array时,必须指明其类型和大小!默认构造的array是非空的,它包含了与其大小一样多的元素
eg: array<int,10>
虽然我们不能对内置数组类型进行拷贝或对象赋值操作,但array无限制,但前提是类型和大小相同,array类型不支持assign也不允许用花括号进行赋值,初始化可以
使用assign(仅顺序容器)
seq.assign(b,e) 将seq中的元素替换成迭代器b和e所表示范围内的元素,b,e不能指向seq中的元素。
seq.assign(li) 将seq中的元素替换成初始化列表il中的元素
seq.assign(n,t) 将seq中的元素替换为n个值为t的元素
assign(b,e)允许我们从一个不同但相容的类型赋值,或者从容器的一个子序列赋值。assign操作用参数所指定的元素拷贝替换左边容器的所有元素。
list<string> names;
vector<const char*> oldstyle;
names = oldstyles;//错误:容器类型不匹配
names.assign(oldstyle.cbegin(),oldstyle.cend());//正确,可以进行类型转换
使用swap
除array外,swap不对任何元素进行拷贝,删除,插入操作,因此可以保证在常数时间内完成。
元素不会移动意味着,除string外,指向容器的迭代器,引用和指针在swap之后都不会失效,所指的变量名换了而已,与其他元素不同,string调用swap会使迭代器,引用和指针失效
vector<string> sec1(10);
vector<string> sec2(20);
auto *iter = &sec1[3]
swap(sec1,sec2);
此时iter从之前的指向sec1[3]变为指向sec2[3];
对于array,在swap操作之后,俩个array会真正交换他们的元素。因此,交换两个array所需的时间与array中的元素数目成正比,切交换之后,指针,引用和迭代器所绑定的元素保持不变
容器大小操作
size: 返回容器中元素个数
max_size: 返回一个大于或等于该容器所能容纳的最大元素数的值
forward_list支持max_size和empty,但不支持size;
关系运算符
每个容器都支持==和!=运算符;除了无序容器外的所有容器都支持关系运算符(>,>=,<,<=)关系运算符左右两边的运算对象必须是相同类型的容器,容器之间的比较与string相同
顺序容器操作
push_back();
emplace_back(); //在尾部创建
push_front();
emplace_front(); //在头部创建
insert(p,t);
emplace(p,args);//在迭代器p指向的元素之前指定位置插入
insert(p,n,t); //在迭代器p指向的元素之前插入n个值为t的元素
insert(p,b,e); //将迭代器b,e指向的范围插入到迭代器p指向的元素之前
insert(p,li); //li是花括号包围的元素值列表,插入到迭代器p之前
向一个vector,string或deque插入元素会使所指向容器的迭代器,引用,指针失效
切记:当我们用一个对象来初始化容器时,或将一个对象插入到容器当中时,实际上放入到容器当中的是对象值的一个拷贝,而不是对象本身。
list、forward_list、deque支持push_front但vector和string不支持push_front
insert()的返回值
返回一个迭代器,指向新插入元素的位置
当调用push或insert成员函数时,我们将元素类型的对象传递给他们,这些对象被拷贝到容器中,而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace
成员使用这些参数在容器管理的内存空间直接构造元素。
push_back将会创建一个局部临时对象,并将其压入容器,emplace的参数必须与构造函数相匹配;
访问元素
at和下标访问只适用于string,vector,deque,array
c.front()返回容器c中的第一个元素,c.back()返回最后一个元素
包括array在内的每个顺序容器都有一个front成员函数,而除forward_list之外的所有顺序容器都有一个back成员函数,不能在空容器中使用该成员函数
c.at(n) 返回下标为n的引用,如果下标越界则抛出out_of_range错误;
在容器中访问元素的成员函数返回的都是引用,如果一个容器时一个const对象,则返回值是const引用
删除元素
forward_list不支持pop_back;vector和string不支持pop_front
c.pop_back() | 删除c中尾元素 |
---|---|
c.pop_front() | 删除c中首元素 |
c.erase§ | 删除迭代器p所指向的元素,返回一个被删除元素之后元素的迭代器 |
c.erase(b,e) | 删除迭代器b,e区间内的元素,返回最后一个被删除元素之后元素的迭代器 |
c.clear() | 删除c中的所有元素 |
删除deque中除首尾位置之外的任何元素都会使所有指针,迭代器,引用失效
指向vector或string中删除点之后的位置的迭代器,引用,指针都会失效
特殊的forward_list操作
lst.before_begin() 返回首元素之前不存在的元素的迭代器,此迭代器不能解引用。
lst.insert_after(p,t) 在迭代器p之后的位置插入迭代器
lst.insert_after(p,n,t) 在迭代器p之后插入n个t元素
lst.insert_after(p,b,e) 插入迭代器区间
emplace_after(p,args) 在p指定位置之后创建一个元素
lst.erase_after§ 删除p指向的位置之后的元素
lst.erase_after(b,e) 删除从b之后到e之间的元素。
改变容器大小
c.resize(n) 调整c的大小为n个元素,若n<c.size(),则多出的元素会被丢弃
c.resize(n,t) 调整c的大小为n个元素,任何新添加的元素都初始化为值t;
容器操作可能使迭代器失效
向容器添加元素后:
- 如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效如果存储空间未重新分配,指向插入位置之前的元素的迭代器,指针和引用仍然有效
- 对于deque,插入到首尾之外的位置都会导致迭代器,指针,引用失效,如果在首位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效
- 对于list和forward_list,指向容器的迭代器,指针,引用依然有效
当删除一个元素后:
- 对于list和forward_list,指向容器的其他位置的迭代器,指针,引用仍有效
- 对于deque,如果在首尾之外的任何位置删除元素,那么指向删除元素外其他元素的迭代器,引用,指针也会失效.如果删除deque的尾元素,则尾迭代器也会失效,但其他迭代器,指针,引用不受影响;如果删除首元素,这些也不会受影响。
- 对于vector和string,指向被删除元素之前的迭代器,引用,指针仍然有效;
- 注意:当我们删除元素时,尾后迭代器总是会失效
不要保存end返回的迭代器
当我们添加/删除vector或string的元素后,或在deque中首元素之外任何位置添加/删除元素后,原来end返回的迭代器总会失效。
Vector对象是如何自动增长
管理容量的成员函数
shrink_to_fit 只适用于vector,string和deque
capacity和resever只适用于vector和string
c.shrink_to_fit() | 将capacity()减少为与size相同的大小 |
---|---|
c.capacity() | 不重新分配空间的话,c可以保存元素的数目 |
c.resever(n) | 分配至少能容纳n个元素的内存空间 |
resever并不改变容器中元素的数目,它仅影响vector预先分配多少内存
每个vector实现都可选择自己的内存分派配策略,但只有当迫不得已的时候才可以分配新的内存
额外改变string的操作
string s(cp,n) s是cp指向的数组的前n个字符的拷贝
string s(s2,pos2) 从下标pos2开始拷贝
string s(s2,pos,len) 从下标pos2拷贝长度len的字符
s.substr(pos,n) 返回一个字符串
append和replace函数
s.append(args) 将args追加到s的尾部
s.replace(range,args) 删除range范围内的元素,替换为args指定的字符
string的搜索操作
string搜索函数返回string::size_type类型值,该类型是一个unsigned类型,因此用一个int或者其他带符号的类型来保存这些函数的返回值可能会出错,应使用auto类型
s.find(args) 查找s中第一次出现的位置
栈适配器stack(先进后出)
栈默认基于deque实现,也可以在list,vector之上实现
s.pop() 删除栈顶元素,但不返回该元素的值
s.emplace(args)
s.push(item) 创建一个新元素压入栈顶
s.top() 返回栈顶元素,但元素不弹出栈
不能在stack上调用顺序容器的成员函数,必须使用自己的
队列适配器queue(先进先出)
queue默认基于deque实现,priority_queue默认基于vector实现
queue也可以用list或vector实现,priority_queue也可以用deque实现
q.pop() 返回queue的首元素或priority_queue的最高优先级
q.front() 返回首元素或尾元素,但不删除此元素
q.back() 只适用于queue
q.top() 返回最高优先级元素
q.emplace(args)
q.push(item) 向队列中添加元素