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 常量       随机

头部操作:表示在第一个元素之前的插入和删除操作。

尾部操作:表示在最后一个元素之后的插入和删除操作。

列表操作:表示在任意位置的插入和删除操作。

迭代器:“随机”表示随机访问迭代器,“向前”表示前向迭代器,“双向”表示双向迭代器。

时间复杂度

  1. 常量又表示为O(1),表示时间复杂度是个常量,通常代表时间复杂度低。
  2. O(n)表示操作花费非时间与元素数目成正比,元素增加n倍,操作时间也增加n倍。通常代表时间复杂度较高。
  3. O(n*n)表示元素增加n倍,操作时间就增加n^2倍。通常代表时间复杂度很高,n很大时,对资源消耗来说是灾难。
  4. O(logn)表示元素增加n倍,操作时间增加logn倍(以2为底的对数)。通常代表时间复杂度较低。
  5. O(nlogn)表示元素增加n倍,操作时间增加nlogn倍。时间复杂度高于O(n)低于O(n*n)。

时间复杂度后加 “+” 表示时间复杂度可能会更高,如vector增加元素时,可能需要重新分配资源。

值得注意的是,操作效率还取决于计算机的内存和处理器构架的细节,比如通过链接获取下一个元素(list情形)的代价会远高于在一个vector中获取下一个元素的代价(元素是连续存储)。因此对操作效率的评估不能完全简单的依赖于对复杂性的评估,而是要进行实际的测试。

2.2、容器赋值、移动

  1. 赋值操作并不拷贝或移动分配器,目标容器获得一组新的元素,但会保留其旧的分配器,新元素的空间也是用此分配器分配的。

  2. 一个构造函数或是一次元素拷贝可能会抛出异常,来指出它无法完成这个任务。

  3. 初始化器的潜在二义性。

    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),而两个指针并非指向相同的数组。记住,对大小初始化器使用(), 而对其它所有初始化器都使用{}

  4. 容器通常都很大,因此几乎总是以引用的方式传递容器实参。但是,由于容器都是资源句柄,因此可以高效的以返回值的方式返回容器(隐含使用移动操作)。类似的不想使用别名时,可以用移动的方式传递容器实参。例如:

    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容器概述的更多相关文章

  1. STL——容器概述

    在实际的开发过程中,数据结构本身的重要性完全不逊于算法的重要性,当程序中存在着对时间要求很高的部分时,数据结构的选择就显得更加重要. 试想:如同栈一样的一条死胡同里停车,这样的效率会很高吗? 经典的数 ...

  2. C++ STL 容器概述

    在STL编程中,容器是经常用到的一种数据结构,在C++标准库中,容器分为: 序列式容器 关联式容器 二者本质区别在于,序列式容器是通过元素在容器中的位置进行顺序存储和元素访问.关联容器则是通过键[ke ...

  3. STL 容器简介

    一.概述 STL 对定义的通用容器分三类:顺序性容器.关联式容器和容器适配器. 顺序性容器是一种各元素之间有顺序关系的线性表.元素在顺序容器中保存元素置入容器时的逻辑顺序,除非用删除或插入的操作改变这 ...

  4. STL容器

    啦啦啦,今天听啦高年级学长讲的STL容器啦,发现有好多东西还是有必要记载的,毕竟学长是身经百战的,他在参加各种比赛的时候积累的经验可不是一天两天就能学来的,那个可是炒鸡有价值的啊,啊啊啊啊啊 #inc ...

  5. c++ stl容器set成员函数介绍及set集合插入,遍历等用法举例

    c++ stl集合set介绍 c++ stl集合(Set)是一种包含已排序对象的关联容器.set/multiset会根据待定的排序准则,自动将元素排序.两者不同在于前者不允许元素重复,而后者允许. 1 ...

  6. STL容器删除元素的陷阱

    今天看Scott Meyers大师的stl的用法,看到了我前段时间犯的一个错误,发现我写的代码和他提到错误代码几乎一模一样,有关stl容器删除元素的问题,错误的代码如下:std::vector< ...

  7. 【转】c++中Vector等STL容器的自定义排序

    如果要自己定义STL容器的元素类最好满足STL容器对元素的要求    必须要求:     1.Copy构造函数     2.赋值=操作符     3.能够销毁对象的析构函数    另外:     1. ...

  8. GDB打印STL容器内容

    GDB调试不能打印stl容器内容,下载此文件,将之保存为~/.gdbinit就可以使用打印命令了. 打印list用plist命令,打印vector用pvector,依此类推. (gdb) pvecto ...

  9. STL容器迭代器失效分析

    连续内存序列容器(vector, string, deque) 对于连续内存序列STL容器,例如vector,string,deque,删除当前iterator会使得后面所有的iterator都失效, ...

随机推荐

  1. Elastic-Job介绍

    1 什么是分布式任务调度 什么是分布式?当前软件的架构正在逐步转变为分布式架构,将单体结构分为若干服务,服务之间通过网络交互来完成用户的业务处理,如下图,电商系统为分布式架构,由订单服务.商品服务.用 ...

  2. Java虚拟机之JVM调节参数

    -XX:+PrintGC 使用这个参数,虚拟机启动后,每次GC就会打印日志. -XX:+UseSerialGC 使用串行垃圾回收器. -XX:+PrintGCDetails 打印详细信息.包括各个区的 ...

  3. Selenium 多窗口切换

    我们在操作网页的时候,点击有些页面的链接,会重新打开一个窗口,我们要在新页面上操作,就得切换窗口 比如在百度首页的登录框点击注册,会重新打开一个注册的新页面,要在新页面注册,就得先切进新页面 那我们怎 ...

  4. CSS 处理溢出强行换行

    CSS折行样式 word-break:break-all;允许单词拆分折行 word-break:keep-all;只能在半角空格或连字符处换行. word-wrap:break-word;在长单词或 ...

  5. 五大主流数字币钱包:imToken数字货币钱包,Bitcoin core钱包,BTS网页版钱包,AToken轻钱包,Blockchain

    AToken数字货币钱包 超容易上手支持五大主流币种   互联网 | 编辑: 王静涛 2017-12-28 09:58:33转载     国家监管部门已叫停数字货币交易,包括火币网.比特币中国.OKC ...

  6. iOS自动化--Spaceship使用实践

    Spaceship ### 脚本操作 证书,app,provision等一些列apple develop后台操作,快速高效. github地址 spaceship开发文档 文档有列出常用的api调用d ...

  7. Spring boot 自定义一个starter pom

    用过springboot的自动配置会觉得非常方便,我们完全可以自己写一个starter pom,这样不仅可以有自动配置功能,而且具有更通用的的耦合度低的配置, 新建一个starter的maven项目, ...

  8. [VBA]批量新建指定名称的工作表

    sub 批量新建指定名称的工作表() Dim i As Integer For i = 2 To 10    '根据实际情况修改i大小 Worksheets.Add after:=Worksheets ...

  9. mac 外接显示屏的坑

    概述 工作中使用 Mac 外接显示屏,有时会出现闪屏然后黑屏的现象,之前都没有找到原因,今天终于找到了,记录下来,供以后参考,相信对其他人也有用. 参考资料: Macbook外接显示器设置教程 问题 ...

  10. JVM监控工具之jmap、jstat、stack、jps、jstatd、jinfo、jhat、jdb

    1.jdb(The Java Debuger) jdb 用来对core文件和正在运行的Java进程进行实时地调试,里面包含了丰富的命令帮助您进行调试,它的功能和Sun studio里面所带的dbx非常 ...