表达式 | 返回类型 | 含义 | 容器 |
a.front() | T& | *a.begin() | vector,list,deque |
a.back() | T& | *--a.end() | vector,list,deque |
a.push_front(t) | void | a.insert(a.begin(),t) | list,deque |
a.push_back(t) | void | a.insert(a.end(),t) | vector,list,deque |
a.pop_front(t) | void | a.erase(a.begin()) | list,deque |
a.pop_back(t) | void | a.erase(a.end()) | vector,list,deque |
a[n] | T& | *(a.begin()+n) | vector,deque |
a.at(n) | T& | *(a.begin()+n) | vector,deque |
表中:t 为 类型为T(存储在容器中的值的类型)的值,n表示整数
1, a[n] 与 a.at(n)都返回一个指向容器中第n个元素(从0开始编号)的引用。
区别:如果n落在容器的有效区间外,则a.at(n)将执行边界检查,并引发out_of _range异常。
2, 为何list与deque定义了a.push_front(),而vector没有定义?
原因:假设要将一个新值插入到包含100个元素的矢量的最前面,要腾出空间,必须将第99个元素移到位置100,然后将第98个元素移到位置99,依此类推,这种操作的复杂性为线性时间,因为移到100个元素所需的时间为移到1个元素所需时间的100倍。但该方法的操作被假设为只有仅当其复杂度为固定时间时才被实现。
vector:
1)是数组的一种类的表示,提供了自动内存管理,可以动态的改变其对象的长度,并随元素的添加与删除而增大或缩小。
2)提供了对元素的随机访问。
3)在尾部添加与删除元素的时间是固定的,但在头部或中间插入和删除元素的复杂度为线性时间。
4)除了序列外,vector还是可反转容器概念的模型,其增加了两个类方法:rbegin(),rend().
5)vector是最简单的序列类型,除非其它类型的特殊优点更能满足程序的要求,否则应默认使用vector.
deque:
1)表示双端队列
2)类似于vector,支持随机访问。
3)从deque对象的开始与尾端位置插入和删除元素的时间是固定的,则不像vector中那样是线性时间。所以如果多数操作发生在序列的起始和结尾处,则应考虑使用deque数据结构
4)为实现在deque两端执行插入与删除操作的时间为固定的这一目的,deque对象的设计比vector对象更为复杂。因此,尽管二者都提供对元素的随机访问和在序列中部执行线性时间的插入和删除操作,但vector容器执行这些操作的速度更快些。
list:
1)表示双向链表,除了第一个元素与最后一个元素,每个元素都与前后的元素相链接,这意味着可以双向遍历链表
2)list与vector之间的区别:
1 -- list在链表中任一位置进行插入和删除的时间都是固定的
vector模板提供了除结尾处外的线性时间的插入与删除,在结尾处提供了固定时间的插入与删除
因此:vector强调的是通过随机访问进行快速访问,而list强调的是元素的快速插入与删除。
2 -- 与vector一样,list也是可反转容器。与vector不同是,list不支持数组表示法与随机访问。
3 -- vector迭代器,在容器中添加或删除元素之后,迭代器指向的位置不变,但数据可能不同。
list迭代器则不移动已有数据,而只是修改链接信息,指向某个元素的迭代器仍然指向该元素,但它链接的元素可能与以前不同。
3)除序列与可反转容器的函数外,list模板还提供了链表专用的成员函数。
函数 | 说明 |
void merge(list<T, Alloc>& x) |
将链表x与调用链表合并。两个链表必须已经排序,合并后的经过排序的链表保存在调用链表中,x为空,
这个函数的复杂度为线性时间
|
void remove(const T& val) | 从链表中删除val的所有实例,这个函数的复杂度为线性时间 |
void sort() | 使用<运算符对链表进行排序:N个元素的复杂度为NlogN |
void splice(iterator pos,list<T,Alloc>x) | 将链表x的内容插入到pos的前面,x为空,这个函数的复杂度为固定时间 |
void unique() | 将连续的相同元素压缩为单个元素,这个函数的复杂度为线性时间。 |
下面是关于这几个函数的实例应用:
#include <iostream>
#include <list> // list
#include <iterator>
#include <algorithm> //for_each
void outint(int n)
{
std::cout << n << " ";
}
int main()
{
using namespace std;
list<int> one(5, 2); // 5个2
int stuff[5] = {1, 2, 4, 8, 6};
list<int> two;
two.insert(two.begin(), stuff, stuff + 5); //从起始位插入stuff所有数据
int more[6] = {6, 4, 2, 4, 6, 5};
list<int> three(two); //复制two到three
three.insert(three.end(), more, more + 6); //从three尾部插入more的所有数据
cout << "List one: ";
for_each(one.begin(), one.end(), outint); // 2 2 2 2 2
cout << endl << "List two: ";
for_each(two.begin(), two.end(), outint); // 1 2 4 8 6
cout << endl << "List three: ";
for_each(three.begin(), three.end(), outint); // 1 2 4 8 6 6 4 2 4 6 5
three.remove(2); // 从three中删除2的所有实例
cout << endl << "List three remove(2): ";
for_each(three.begin(), three.end(), outint); // 1 4 8 6 6 4 4 6 5
three.splice(three.begin(), one); // 将one的内容插入到three的相应位置,并清空原one的内容
cout << endl << "List three splice: ";
for_each(three.begin(), three.end(), outint); // 2 2 2 2 2 1 4 8 6 6 4 4 6 5
cout << endl << "List one: ";
for_each(one.begin(), one.end(), outint); //输出为空,被splice清空了
three.unique(); //将three中连续相邻的相同元素压缩为单个元素
cout << endl << "List three unique: ";
for_each(three.begin(), three.end(), outint); // 2 1 4 8 6 4 6 5
three.sort(); // 排序,默认从低到高
cout << endl << "List three sort: ";
for_each(three.begin(), three.end(), outint); // 1 2 4 4 5 6 6 8
three.unique(); // 去重,只去相邻的
cout << endl << "List three sort & unique: ";
for_each(three.begin(), three.end(), outint); // 1 2 4 5 6 8
two.sort();
cout << endl << "List two: ";
for_each(two.begin(), two.end(), outint); // 1 2 4 6 8
three.merge(two); //该函数要求调用者与被调用者必须先排序,输出为两者一起并从低到高排序,相当于合并后sort
cout << endl << "sort List two merge into List three: ";
for_each(three.begin(), three.end(), outint); //1 1 2 2 4 4 5 6 6 8 8
cout << endl << "List two: ";
for_each(two.begin(), two.end(), outint); // 输出为空,被merge清空了
cout << endl;
return 0;
}
注意点:
splice与insert的主要区别:insert将原始区间的副本插入到目标位置,而splice则将原始区间移到了目标位置,所以上例中one被splice后为空。
unique:只去掉相邻的重复的,不相邻不则不去,想去掉不相邻的,只有先调用sort
forward_list (C++11):
容器类forward_list实现了单链表,在这种链表中,每个节点都只链接到下一个节点,而没有链接到前一个节点。
因此,forward_list只需正向迭代器,不需双向迭代器。
所以不同于vector与list,forward_list是不可反转的容器。但forward_listg更简单,更紧凑,但功能也更少。
queue头文件:
1)queue模板类是一个适配器类,其让底层展示典型的队列接口。
queue模板的限制比deque更多,它不仅不允许随机访问,甚至不允许遍历队列。
它把使用限制在定义队列的基本操作上,可以将元素添加到队尾,从队首删除元素,查看队首和队尾的值,检查元素数目和测试队列是否为空。
方法 | 说明 |
bool empty() const | 如果队列为空,则返回true,否则返回false |
size_type size() const | 返回队列中元素的数目 |
T& front() | 返回指向队首元素的引用 |
T& back() | 返回指向队尾元素的引用 |
void push(const T& x) | 在队尾插入x |
void pop() | 删除队首元素 |
2)priority_queue 模板类是另一个适配器类,它支持的操作与queue相同,
两者区别:
在priority_queue中,最大的元素被移到队首,内部区别在于,默认的底层类是vector
stack :
与queue相似,stack也是一个适配器类,它给底层类(默认的底层类是vector)提供了典型的栈接口。
stack模板的限制比vector更多,它不仅不允许随机访问栈元素,甚至不允许遍历栈。
它把使用限制在定义栈的基本操作上,即可以将压入推到栈顶,从栈顶弹出元素,查看栈顶的值,检查元素数目,和测试栈是否为空。
方法 | 说明 |
size_type size() const | 返回栈中的元素数目 |
T& top() | 返回指向栈顶元素的引用 |
bool empty() const | 如果栈为空,则返回true,否则返回false |
void push(const T& x) | 在栈顶部插入x |
void pop() | 删除栈顶元素 |
array:
头文件:array
它并非STL容器,因为其长度是固定的,
因此,array没有定义调整容器大小的操作,如push_back() 和 insert()
但,定义了对它来说有意义的成员函数,如operator[ ]() 和 at()
也可以将很多STL的算法应用于array对象,如copy() 与 for_each()