请你说一说STL常用的容器
参考回答:
vector是一种动态数组,在内存中具有连续的存储空间,支持快速随机访问。由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢。vector有多个构造函数,默认的构造函数是构造一个初始长度为0的内存空间,且分配的内存空间是以2的倍数动态增长的,即内存空间增长是按照20,21,22,23.....增长的,在push_back的过程中,若发现分配的内存空间不足,则重新分配一段连续的内存空间,其大小是现在连续空间的2倍,再将原先空间中的元素复制到新的空间中,性能消耗比较大,尤其是当元素是非内部数据时(非内部数据往往构造及拷贝构造函数相当复杂)。
API:
vector <T> v;//采用模板实现类实现,默认构造函数
assign(begin(),end());//将【begin(),end()】区间中的元素拷贝给本身
size();//返回元素容器中元素个数
at(int idx);//返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
(2)deque
deque和vector类似,支持快速随机访问。二者最大的区别在于,vector只能在末端插入数据,而deque支持双端插入数据。deque的内存空间分布是小片的连续,小片间用链表相连,实际上内部有一个map的指针。deque空间的重新分配要比vector快,重新分配空间后,原有的元素是不需要拷贝的。
API:
deque<T>deqT;//默认构造形式
assign(begin,end);//将【begin,end】区间的数据拷贝赋值给自身
deque.size();//返回容器中元素的个数
push_back(elem);//在容器尾部添加一个数据
(3)list
list是一个双向链表,因此它的内存空间是可以不连续的,通过指针来进行数据的访问,这使list的随机存储变得非常低效,因此list没有提供[]操作符的重载。但list可以很好地支持任意地方的插入和删除,只需移动相应的指针即可。
API:
list<T>lstT;//list采用模板类实现对象的默认构造函数
push_back(elem);//在容器尾部加入一个元素
size();//返回元素容器中元素个数
empty();//判断容器是否为空
(4)map
map是一种关联容器,该容器用唯一的关键字来映射相应的值,即具有key-value功能。map内部自建一棵红黑树(一种自平衡二叉树),这棵树具有数据自动排序的功能,所以在map内部所有的数据都是有序的,以二叉树的形式进行组织。
API:
map<t1,T2>mapT;//map默认构造函数
size();//返回元素中元素的数目
empty();//判断容器是否为空
clear();//删除所有元素
(5)set
set也是一种关联性容器,它同map一样,底层使用红黑树实现,插入删除操作时仅仅移动指针即可,不涉及内存的移动和拷贝,所以效率比较高。set中的元素都是唯一的,而且默认情况下会对元素进行升序排列。所以在set中,不能直接改变元素值,因为那样会打乱原本正确的顺序,要改变元素值必须先删除旧元素,再插入新元素。不提供直接存取元素的任何操作函数,只能通过迭代器进行间接存取。
API:
set<T>sT;//set默认构造函数
size();//返回容器中元素的数目
empty();//判断容器是否为空
insert(elem);//在容器中插入元素
clear();//清除所有元素
(6)queue
queue是一个队列,实现先进先出功能,queue不是标准的STL容器,却以标准的STL容器为基础。queue是在deque的基础上封装的。之所以选择deque而不选择vector是因为deque在删除元素的时候释放空间,同时在重新申请空间的时候无需拷贝所有元素。
API:
queue<T>queT;//queue采用模板类实现,queue对象的默认构造形式
push(elem);//往队尾添加元素
(7)stack
stack是实现先进后出的功能,和queue一样,也是内部封装了deque,这也是为啥称为容器适配器的原因吧(纯属猜测)。自己不直接维护被控序列的模板类,而是它存储的容器对象来为它实现所有的功能。stack的源代码原理和实现方式均跟queue相同。
API:
stack<T>stkT;//采用模板类实现,stack对象的默认构造形式
push(elem);//向栈顶添加元素