STL容器概述
STL容器
1、容器概述
1.1、容器分类
1.1.1、顺序容器:提供对元素序列的访问,顺序容器为元素连续分配内存或将元素组织为链表,元素的类型是容器成员value_type。
顺序容器 | 说明 |
---|---|
vector<T, A> | 空间连续分配的T类型元素序列;默认选择容器 |
list<T, A> | T类型元素双向链表;当需要插入/删除元素但不移动已有元素是选择它。 |
forward_list<T, A> | T类型元素单向链表;很短的或空序列的理想选择 |
deque<T, A> | T类型元素双向队列;向量和链表的混合;对于大多数应用,都比向量和链表其中之一要慢。 |
模板参数A是一个分配器,容器用它来分配和释放内存, 默认值 std::allocator。
1.1.2、有序关联容器:提供基于关键字的关联查询。
有序关联容器 | 说明 |
---|---|
map<K, V, C, A> | 从K到V的有序映射;一个(K, V)对序列 |
multimap<K, V, C, A> | 从K到V的有序映射;允许重复关键字 |
set<K, C, A> | K的有序集合 |
multiset<K, C, A> | K的有序集合;允许重复关键字 |
C是比较类型,默认值 std::less(K); A是分配器类型,默认值 std::allocator<std::pair<const K, T>>。这些容器通常采用平衡二叉树(通常红黑树)实现。
1.1.3、无序关联容器:
有序关联容器 | 说明 |
---|---|
unordered_map<K, V, H, E, A> | 从K到V的无序映射; |
unordered_multimap<K, V, H, E, A> | 从K到V的无序映射;允许重复关键字 |
unordered_set<K, H, E, A> | K的无序集合 |
unordered_multiset<K, H, E, A> | K的无序集合;允许重复关键字 |
H是关键字类型K的哈希函数类型,默认值 std::hash。E是关键字类型K的相等性测试函数类型, 默认值 std::equal_to, 用来判断哈希值相同的两个对象是否相等。A是分配器类型。这些容器都是采用溢出链表法的哈希表实现。
关联容器都是链接结构(树),节点类型为其成员value_type。
1.1.4、容器适配器:提供对底层容器的特殊访问。
容器适配器 | 说明 |
---|---|
priority_queue<T, C, Cmp> | T的优先队列;Cmp是优先级函数类型 |
queue<T, C> | T的队列,支持push() 和 pop()操作 |
stack<T, C> | T的栈,支持push() 和 pop()操作 |
一个priority_queue的默认优先级函数Cmp为std::less。queue的默认容器类型C为std::deque,stack和priority_queue的默认容器类型C为std::vector。
1.2、容器对元素的要求
1.2.1、比较操作
注意 C 风格字符串(即const char*)上的 < 比较的是指针值,因此如果用 C 风格字符串作为关键字,关联容器将不能正常工作,为了让这样的关联容器正常工作,就必须使用基于字典序的比较操作。
struct Cstring_less
{
bool opreator()(const char *p, const char *q) const
{
return strcmp(p, q) < 0;
}
};
map<char*, int, Cstring_less> m; //map使用strcmp()比较const
2、操作
2.1、标准库容器操作复杂性
标准容器操作复杂性 | |||||
[] | 列表 | 头部 | 尾部 | 迭代器 | |
vector | 常量 | O(n)+ | 常量+ | 随机 | |
list | 常量 | 常量 | 常量 | 双向 | |
forward_list | 常量 | 常量 | 前向 | ||
deque | 常量 | O(n) | 常量 | 常量 | 随机 |
stack | 常量 | ||||
queue | 常量 | 常量 | |||
priority_queue | O(log(n)) | O(log(n)) | |||
map | O(log(n)) | O(log(n))+ | 双向 | ||
multimap | O(log(n))+ | 双向 | |||
set | O(log(n))+ | 双向 | |||
multimap | O(long(n))+ | 双向 | |||
unordered_map | 常量+ | 常量+ | 前向 | ||
unordered_multimap | 常量+ | 前向 | |||
unordered_set | 常量+ | 前向 | |||
unordered_multiset | 常量+ | 前向 | |||
string | 常量 | O(n)+ | O(n)+ | 常量+ | 随机 |
array | 常量 | 随机 | |||
内置数组 | 常量 | 随机 | |||
valarray | 常量 | 随机 | |||
bitset | 常量 | 随机 |
头部操作:表示在第一个元素之前的插入和删除操作。
尾部操作:表示在最后一个元素之后的插入和删除操作。
列表操作:表示在任意位置的插入和删除操作。
迭代器:“随机”表示随机访问迭代器,“向前”表示前向迭代器,“双向”表示双向迭代器。
时间复杂度:
- 常量又表示为O(1),表示时间复杂度是个常量,通常代表时间复杂度低。
- O(n)表示操作花费非时间与元素数目成正比,元素增加n倍,操作时间也增加n倍。通常代表时间复杂度较高。
- O(n*n)表示元素增加n倍,操作时间就增加n^2倍。通常代表时间复杂度很高,n很大时,对资源消耗来说是灾难。
- O(logn)表示元素增加n倍,操作时间增加logn倍(以2为底的对数)。通常代表时间复杂度较低。
- O(nlogn)表示元素增加n倍,操作时间增加nlogn倍。时间复杂度高于O(n)低于O(n*n)。
时间复杂度后加 “+” 表示时间复杂度可能会更高,如vector增加元素时,可能需要重新分配资源。
值得注意的是,操作效率还取决于计算机的内存和处理器构架的细节,比如通过链接获取下一个元素(list情形)的代价会远高于在一个vector中获取下一个元素的代价(元素是连续存储)。因此对操作效率的评估不能完全简单的依赖于对复杂性的评估,而是要进行实际的测试。
2.2、容器赋值、移动
赋值操作并不拷贝或移动分配器,目标容器获得一组新的元素,但会保留其旧的分配器,新元素的空间也是用此分配器分配的。
一个构造函数或是一次元素拷贝可能会抛出异常,来指出它无法完成这个任务。
初始化器的潜在二义性。
void use()
{
vector<int> vi{1, 3, 5, 7, 9}; //使用5个整数初始化vector
vector<string> vs(7); //vector初始化为7个空字符串,初始化大小 vector<int> vi2;
vi2 = {2, 4, 6, 8}; //将4个整数赋予vi2
vi2.assign(&vi[1], &vi[4]); //将序列3,5,7赋予vi2 vector<string> vs2;
vs2 = {"hello", "world"}; //赋予vs2两个字符串
vs2.assign("First", "Second"); //运行时错误
}
以上代码中,向vs2赋值时发生的错误时传递了一对指针(而不是一个initalizer_list),而两个指针并非指向相同的数组。记住,对大小初始化器使用(), 而对其它所有初始化器都使用{}。
容器通常都很大,因此几乎总是以引用的方式传递容器实参。但是,由于容器都是资源句柄,因此可以高效的以返回值的方式返回容器(隐含使用移动操作)。类似的不想使用别名时,可以用移动的方式传递容器实参。例如:
void task(vector<int>&& v);
//以返回值的方式返回容器,隐式使用移动操作
vector<int> user(vector<int> &large)
{
vector<int> res;
//...
task(move(large)); //将数据所有权传递给task(),用移动的方式传递容器实参。
//...
return res;
}
2.3、容器的大小和容量
大小:指容器中的元素数目。
容量:指重新分配更多内存之前容器能够保存的元素数目。
大小和容量 | |
x = c.size() | x是c的元素数目 |
c.empty() | c为空吗? |
x = c.max_size() | x是c的最大可能元素数目 |
x = c.capacity() | x是为c分配的空间大小;只适用于vector和string |
c.reserve(n) | 为c预留n个元素的空间;只适用于vector和string |
c.resize(n) | 将c的大小改变为n;将增加的元素初始化为默认元素值;只适用于顺序容器和string |
c.resize(n, v) | 将c的大小改变为n;将增加的元素初始化为v;只适用于顺序容器和string |
c.shrink_to_fit() | 令c.capacity()等于c.size();只适用于vector、deque、string |
c.clear() | 删除c的所有元素 |
注意,在改变大小或容量时,元素可能会被移动到新的存储位置。这意味着指向元素的迭代器(以及指针和引用)可能会失效(即指向旧元素的位置)。
指向关联容器(如map)元素的迭代器只有当所指元素从容器中删除(erase())时才会失效。与之相反,指向顺序容器(如vector)元素的迭代器当元素重新分配空间(如resize()、reverse()、push_back())或所指元素在容器中移动(如在前一个位置发生了erase()或insert())时也会失效。
2.4、迭代器
容器可以看做按容器迭代器定义的顺序或相反的顺序排列的元素序列。对于一个关联容器,元素的顺序由容器比较标准决定。
迭代器 | |
p = c.begin() | p指向c的首元素 |
p = c.end() | p指向c的尾后元素 |
p = c.cbegin() | p指向c的首元素,常量迭代器 |
p = c.cend() | p指向c的尾后元素,常量迭代器 |
p = c.rbegin() | p指向c的反序的首元素 |
p = c.rend() | p指向c的反序的尾后元素 |
p = c.crbegin() | p指向c的反序的首元素,常量迭代器 |
p = c.crend() | p指向c的反序的尾后元素,常量迭代器 |
更多STL容器细节参考:cplusplus
STL容器概述的更多相关文章
- STL——容器概述
在实际的开发过程中,数据结构本身的重要性完全不逊于算法的重要性,当程序中存在着对时间要求很高的部分时,数据结构的选择就显得更加重要. 试想:如同栈一样的一条死胡同里停车,这样的效率会很高吗? 经典的数 ...
- C++ STL 容器概述
在STL编程中,容器是经常用到的一种数据结构,在C++标准库中,容器分为: 序列式容器 关联式容器 二者本质区别在于,序列式容器是通过元素在容器中的位置进行顺序存储和元素访问.关联容器则是通过键[ke ...
- STL 容器简介
一.概述 STL 对定义的通用容器分三类:顺序性容器.关联式容器和容器适配器. 顺序性容器是一种各元素之间有顺序关系的线性表.元素在顺序容器中保存元素置入容器时的逻辑顺序,除非用删除或插入的操作改变这 ...
- STL容器
啦啦啦,今天听啦高年级学长讲的STL容器啦,发现有好多东西还是有必要记载的,毕竟学长是身经百战的,他在参加各种比赛的时候积累的经验可不是一天两天就能学来的,那个可是炒鸡有价值的啊,啊啊啊啊啊 #inc ...
- c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例
c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...
- STL容器删除元素的陷阱
今天看Scott Meyers大师的stl的用法,看到了我前段时间犯的一个错误,发现我写的代码和他提到错误代码几乎一模一样,有关stl容器删除元素的问题,错误的代码如下:std::vector< ...
- 【转】c++中Vector等STL容器的自定义排序
如果要自己定义STL容器的元素类最好满足STL容器对元素的要求 必须要求: 1.Copy构造函数 2.赋值=操作符 3.能够销毁对象的析构函数 另外: 1. ...
- GDB打印STL容器内容
GDB调试不能打印stl容器内容,下载此文件,将之保存为~/.gdbinit就可以使用打印命令了. 打印list用plist命令,打印vector用pvector,依此类推. (gdb) pvecto ...
- STL容器迭代器失效分析
连续内存序列容器(vector, string, deque) 对于连续内存序列STL容器,例如vector,string,deque,删除当前iterator会使得后面所有的iterator都失效, ...
随机推荐
- mac 下 git log 退出方法
英文状态下按 Q (大小写无论)即可.
- Linux安装vsftpd及配置详解
1 安装vsftpd组件 安装完后,有/etc/vsftpd/vsftpd.conf 文件,是vsftp的配置文件.[root@bogon ~]# yum -y install vsftpd 2.FT ...
- 跨平台迁移数据库windows-Linux
将10.10.1.127服务器的数据库ORCL(WINDOWS)迁移到VM 10.10.10.168LINUX平台 操作系统:Windows server 2008r2 64bit CentOS L ...
- 在一个tomcat中配置多个tomcat服务器 111
<Service name="Tomcat_1"> <Connector port="8888" protocol="HTT ...
- WebApi系列知识总结
WebApi系列知识 一.webApi项目搭建 1.新建WebApi项目 (1) (2) (3) (4) Areas – HelpPage – App_Start – HelpPageConfig.c ...
- IDEA 中常用快捷键的使用
IDEA 中快捷键的使用 1:知道类名全局查找类: Ctrl+Shift+Alt+N; 全局搜索: Ctrl+Shift+R 2:快速定位到类的文件夹: 3: 优化导入的类和包 (删除 ...
- Powershell + HTA
众所周知,Powershell早已被集成到了windows的环境中,国外大牛玩得不亦乐乎,而国内圈子却很少听到讨论Powershell的,HTA更不用说了,不是学计算机的或许根本不知道这是什么鬼 Li ...
- 三、robotframework封装的关键字-数据库使用
1. 从数据库查询结果: 数据库连接:Connect To Database Using Custom Params 用法:Connect To Database U ...
- eclipse有时候导入了包,但是还是有红线,找不到
clean一下工程,选择project->clean->clean project selected blow并且选择build only the selected project
- fiddler之请求过滤(Filters)
开启fiddler后,会监听所有的请求,在大多数情况下,我们只需要监听部分请求,此时可以使用Filters功能去控制. 界面显示如下: 默认情况下过滤是未开启的,需要勾选“user filters”进 ...