STL相关知识整理

STL

C++ 标准模板库的核心包括以下三个组件:

组件描述
容器容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。
算法算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。
迭代器迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。

1 vector

1.1 底层原理

vector底层是⼀个动态数组,包含三个迭代器,start和finish之间是已经被使⽤的空间范围,end_of_storage是整
块连续空间包括备⽤空间的尾部。

  • vector内存增⻓机制
    当空间不够装下数据(vec.push_back(val))时,会⾃动申请另⼀⽚更⼤的空间(1.5倍或者2倍),然后把原来的
    数据拷⻉到新的内存空间,接着释放原来的那⽚空间。
    扩充的过程并不是直接在原有空间后⾯追加空间,⽽是新申请⼀块连续空间,将原有的数据拷⻉到新空间中,再
    释放原有空间,完成⼀次扩充。

需要注意的是,每次扩充是重新开辟的空间,所以扩充后,原有的迭代器将会失效,当释放或者删除(vec.clear())⾥⾯的数据时,其存储空间不释放,仅仅是清空了⾥⾯的数据。对vector的任何操作⼀旦引起了空间重新配置,指向原vector的所有迭代器会都失效了。

1.2 应用场景

vector可以随机存储元素(即可以通过公式直接计算出元素地址,而不需要挨个查找),但在非尾部插入删除数据时,效率很低,适合对象简单,对象数量变化不大,随机访问频繁。

1.3 相关问题

  • std::vector的底层(存储)机制:
    vector就是一个动态数组,里面有一个指针指向一片连续的内存空间,当空间不够装下数据时,会自动申请另一片更大的空间(一般是增加当前容量的50%或100%),然后把原来的数据拷贝过去,接着释放原来的那片空间;当释放或者删除里面的数据时,其存储空间不释放,仅仅是清空了里面的数据。
  • std::vector的自增长机制:
    当已经分配的空间不够装下数据时,分配双倍于当前容量的存储区,把当前的值拷贝到新分配的内存中,并释放原来的内存。
  • 为什么vector的插入操作可能会导致迭代器失效?
    vector动态增加大小时,并不是在原空间后增加新的空间,而是以原大小的两倍在另外配置一片较大的新空间,然后将内容拷贝过来,并释放原来的空间。由于操作改变了空间,所以迭代器失效。
  • 调用成员函数push_back时,其内部的内存是如何分配的?
    该函数首先检查是否还有备用空间,如果有就直接在备用空间上构造元素,并调整迭代器finish,使vector变大。如果没有备用空间了,就扩充空间(重新配置、移动数据、释放原空间。)

2 list

2.1 底层原理

list的底层是一个双向链表,以结点为单位存放数据,结点的地址在内存中不一定连续,每次插入或删除一个元素,就配置或释放一个元素空间。
  list不支持随机存取,如果需要大量的插入和删除,而不关心随即存取

2.2应用场景

适用大量的插入和删除,而不关心随机存取

2.3 list与vector的区别

  • 在list的任何位置执行插入和移除都非常快,插入和删除动作不影响指向其它元素的指针,引用,迭代器,不会造成失效;
  • list不支持随机存取,不提供成员函数at()和操作符operator[],可以使用迭代器进行元素的访问;vector支持
  • list没有提供容量,空间重新分配等操作函数,每个元素都有自己的内存;
  • list也提供了特殊成员函数,专门用于移动元素.

3 deque

3.1 底层原理

一个双向开口的连续线性空间:双端队列,在头尾两端进行元素的插入跟删除操作都有理想的时间复杂度。
deque动态地以分段连续空间组合而成,随时可以增加一段新的连续空间并链接起来。不提供空间保留功能。
提供随机访问,同时具有与vector一模一样的接口。不同的是Deque的dynamic array头尾都是开放的,因此可以在两端进行快速的插入和删除。

3.2 应用场景

  • 移除和插入操作发生在首尾两端(Deque的特性决定了该操作效率惊人);
  • 无须迭代器指向其元素(Deque扩容机制导致了其迭代器更容易失效);
  • 要求不再使用的元素必须释放(Deque能够释放不使用的内存块,但C++ standard并不保证这一点,依赖于编译器实现)。

4 map

4.1 map

4.1.1 底层原理

map属于关联容器,提供一对一映射的数据处理能力。底层是由红黑树实现的,具有自动排序能力。因此map内部的所有数据是有序的

4.1.2 特点
  • key不允许重复,关键字唯一
  • 默认自动按照key值升序排序
  • 不能修改key值
  • 支持下标访问[]:但是下标访问的数据不存在的时候自动插入。。(容易写出来坑)
4.1.3 应用场景

key-value类型数据
频繁查找

4.2 multimap

  • 跟map的区别就是key可以重复
  • 不支持下标访问,不支持.at

4.3 hash_map 与 unordered_map

由于在C++标准库中没有定义散列表hash_map,标准库的不同实现者将提供一个通常名为hash_map的非标准散列表。因为这些实现不是遵循标准编写的,所以它们在功能和性能保证上都有微妙的差别。
从C++11开始,哈希表实现已添加到C++标准库标准。决定对类使用备用名称,以防止与这些非标准实现的冲突,并防止在其代码中有hash_table的开发人员无意中使用新类。
所选择的备用名称是unordered_map,它更具描述性,因为它暗示了类的映射接口和其元素的无序性质。
可见hash_map , unordered_map本质是一样的,只不过 unordered_map被纳入了C++标准库标准。

4.3.1 底层原理

底层是哈希表,因此其元素的排列顺序是杂乱的,无序的,不会自动排序

  • unordered_map与map的对比
    存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的,而map中的元素是按照二叉搜索树存储(用红黑树实现),进行中序遍历会得到有序遍历。所以使用时map的key需要定义operator<。而unordered_map需要定义hash_value函数并且重载operator==。但是很多系统内置的数据类型都自带这些。
      总结:结构体用map重载<运算符,结构体用unordered_map重载==运算符。

  • unordered_map与hash_map对比
    unordered_map原来属于boost分支和std::tr1中,而hash_map属于非标准容器。
    unordered_map感觉速度和hash_map差不多,但是支持string做key,也可以使用复杂的对象作为key。
    unordered_map编译时gxx需要添加编译选项:–std=c++11

4.3.2 map 与unordered_map使用选择
  • map

  • 优点:(1)map是有序的(2)基于红黑树实现,查找的时间复杂度是O(n)

  • 缺点:空间占用率比较高,因为内部实现了红黑树,虽然提高了运行效率,但是每个节点都要保存父亲节点和孩子节点和红黑树的性质,使得每一个节点都占用大量的空间。

  • 适用的情况:对于要有序的结构,适用map

  • unordered_map

  • 优点:因为内部是哈希表来实现的,所以查找效率会非常高时间复杂度O(1)

  • 缺点:哈希表的建立比较费时

  • 适用的情况:对于查找问题,适用unordered_map会更好一点。

4.4 hash_multimap 与 unordered_multimap

unordered_multimap 是一个封装哈希表的无序容器。容器中每个元素都是 key/value,每个 key 可重复出现。
同map和unordered_map区别一样,multimap通过key访问单个元素的速度通常也比unordered_multimap容器慢。

4.5 总结

map 与 unorder_map:
map的内存使用比较unorder_map低,但是查找效率也低。
map有序unordered_map无序

在关键字类型的元素没有明显的序的情况下,或者在某些应用中,维护元素有序的代价非常高昂,采用无序容器代替map来说效果会好

map与multimap:
就是键值对可不可以重复的区别。

5 set

5.1 set

底层是红黑树,set 是关联容器的一种,是排序好的集合(元素已经进行了排序)。
set 和 multiset 类似,它和 multiset 的差别在于 set 中不能有重复的元素。multiset 的成员函数 set 中也都有。
不能直接修改 set 容器中元素的值。因为元素被修改后,容器并不会自动重新调整顺序,于是容器的有序性就会被破坏,再在其上进行查找等操作就会得到错误的结果。因此,如果要修改 set 容器中某个元素的值,正确的做法是先删除该元素,再插入新元素。

5.1.1 set与map区别

set相当于只存了map的key值,只是一个序列容器
map存的是键值对,是一个映射

5.2 multiset

允许重复的set

5.3 hash_set与unordered_set

底层是哈希表

5.4 hash_multiset 与 unordered_multiset

允许重复的哈希表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值