C++标准模板库 STL中常见容器总结 侯捷 STL体系结构视频课堂笔记

STL中的六大部件
在这里插入图片描述
(1)容器
(2)分配器
(3)算法
(4)迭代器
(5)适配器
(6)仿函数
这六大部件中,我们一般直接使用的是容器、算法和迭代器以及仿函数。其中算法通过迭代器对容器中的元素进行操作。所以实际上各类部件是相互作用的关系。知己知彼才能更好的使用各个部件。推荐去看侯捷老师的STL体系结构与内核分析这一门课,我自己听完之后感觉受益匪浅。
接下来开始总结常见容器:

一、简述

在这里插入图片描述
容器可以分类为**sequence container **和 **associative container **(关联容器(key和value))以及 unordered container(不定序容器(集合),元素在容器中无序,哈希实现)。图中红色圈起来的部分是c++11中新添加的部分。

**sequence container **

Array:大小是静态的,不能够修改的。
Vector:自动动态内存扩充,使用者不需要关心vector的大小,只需要把元素放进去就行了,但实际上需要考虑内存的扩充需要把元素进行搬移的消耗。
List:双向链表(事实上是双向环状链表)。
Forward-list:单向链表。
(note:使用链表的时候需要注意list的内存比forward-list的内存大的多,所以当功能要求不大时,使用forwwad-list就够了)

Associative container

Set/Multiset: Key就是value,value就是key。(1)set放的元素不能重复,multiset的元素可以重复
Map/Multimap:每一个结点都有key和value(1)map放的元素不能重复,multimap的(key)可以重复
(note:由于红黑树结构的优势,所以大多编译器的标准库都使用红黑树结构来实现以上两种方式。)

unordered container

Unordered Set/Multiset
Unordered map/Multimap

在这里插入图片描述

二、各个容器的底层结构(源码分析)

1、list容器
在这里插入图片描述
主要看这里的__list_node的结构和list——iterator的结构,右上角的代码框可以看到链表中的结点的结构为一个pre指针和一个next指针以及一个数据域,这也是我们熟知的双向链表的结构,这里补充一点容器都是前闭后开区间,所以可以看到这里的结构图中,end()指向的结点是灰色的,是一个虚结点,就是为了满足前闭后开的性质。
顺便介绍一下iterator的原则:

在这里插入图片描述
其中后面的两种几乎没有使用过。
Iterator_category:分类,移动性质,有的迭代器只能++、–,有的迭代器可以跳着走…这就是迭代器的性质。(list不能像数组那要可以通过下标直接访问,只能一个接着一个进行遍历,所以它的iterator只能进行++或 – ,像array、vector这样的内存空间联系,支持随机访问的容器所对应的iterator就是可以+5、+n这样进行访问的。
Value_type:容器内部的元素的数据类型
Difference_type:两个迭代器之间的距离需要用什么数据类型来表现,比如用int够不够表示?或者unsigned int够不够来表现?还是说需要long类型才能表示。
其他两个几乎不用。
这几个是iterator向算法提供的回答,就是说算法会去问迭代器这些值,iterator需要回答这几个问题。

2、vector容器

在这里插入图片描述
//看左边的内存示意图可以看到capacity和size的关系,可以看到capacity比size要大一些,当使用的空间大过了capacity之后,需要进行扩展,在linux里是呈两倍增长,VS中是1.5倍增长。而且内存进行扩展之后,需要把原来的元素全部搬移到新的空间去,所以可以体会出我们使用vector的时候最好先预测好所需要的内存空间大小,然后预先分配好,尽量避免内存的扩充。
这里推荐一个网站,http://cplusplus.com/查看各个容器简单信息。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
vector实际上就是一个数组,但是是动态增长的,而且内置了许多方法可以可以直接调用,通过使用vector之后就会感受到容器存在的意义就是方便我们使用…

3、deque容器
在这里插入图片描述
//iterator在每一次的前进过程中,都需要判断是否已经到达了边界,如果到达了边界,就应该到达下一个缓冲区。所以看之前的ppt可以发现,end()指向的实际上是虚元素,当指向边界时,指针就会指向中控中心(图中的map),然后由中控中心指向下一个缓冲区。如图所示。
//之前一直不理解这里的缓冲区,其实是为了减轻内存的负担设置的。缓冲区随着申请次数的增加,每一次所分配的缓冲区大小也会逐渐增长,8,16,64指数增长。从缓冲区来增大存储空间当然会比从内存获取的效率高很多。

在这里插入图片描述
可以看到这里的map_pointer map;就是我们图中所说的中控中心。
//上面的注解,主要是说明buffer的大小可以人为指定。具体看代码。
在这里插入图片描述
4、set、multiset容器
在这里插入图片描述
//这一页ppt就是强调 set/multiset 的value就是key,所以不能通过iterator来修改结点的值。但是本质上这是由于红黑树的性质的决定的,红黑树中结点的值不能随意的改变,不然会破坏树的高度平衡性。
//散列表的特点就是每一个元素的value = key + data,key是唯一的值,通过key可以快速的找到对应的元素。不过对于set和multiset来说其key就是value,所以value不能随便的改。

在这里插入图片描述
//set容器底层使用了rb_tree的结构,可以看到右边的三个框框的使用,第一个是我们使用set容器的标准方式,我们只用指明一个key的类型,然后其他的两个参数有默认值,然后从而决定set中的key_type和value_type,从而确定rb_tree中的5个值…
//然后再看ppt中的最后一句代码,这里把iterator定义为了const_类型,就是为了防止使用者通过iterator修改value的值。
在这里插入图片描述
//multiset可以允许重复元素。
5、map、multimap
在这里插入图片描述
//例如,一个学生的学号可以设置为key,学生的成绩设置为value。Key是不可以修改的,而value是可以修改的。
//注意看这里文字的第一段,这里说map和multimap容器有元素自动排序的特性。排序的依据是key。以后需要用到有序数组时可以考虑使用这个容器。

在这里插入图片描述
//select1st()函数,就是选择出容器中的第一个元素。是gunC独有的。其他的编译器可能没有。
//可以看到这里的随后一句迭代器的定义,没有指定const类型,也就是可以进行修改的。
//然后另一个与set不同的是,使用map容器需要指定key和data(value)的类型共两个类型。
在这里插入图片描述
//需要自己把key和value包装成pair在放进容器中去。
//不能使用c[key]来直接修改value。与下面讲的map可以进行对比。
在这里插入图片描述
//这里展示了map容器直接通过c[key] = value。来修改或插入新的元素。
//可以与multimap需要先把key和value封装为pair再放进multimap中去进行比较。可以发现这种方法更方便使用者使用,不过在时间上可以看到运算符[]重载的函数中看到,需要先进行排序和二分查找再进行插入,会比multimap直接使用insert会慢一点。
6、hashtable

在这里插入图片描述
//上图解释了hashtable的问题冲突情况——空间不足。

在这里插入图片描述
//为了解决哈希表的冲突问题,
//第一步:每一个篮子设置为链表separate chaining,使产生冲突的元素统一放在该篮子下。但是这遇到了另一个问题是——一直放元素后可能会造成篮子的链表过长,这也会减慢查找效率。
//第二步:当篮子中的链表长度大于当前篮子的个数时(假设一开始篮子的个数为53个,当其中一个篮子的链表有54个结点的时候),就把篮子的个数增大一倍,53-》97。
//第三步:然后进行rehash ing(再散列),也就是原本的元素比如是59%53而找到对应的位置的,现在需要把所有元素key%97,再找到对应的位置放到对应的篮子中去。
//但事实上篮子的个数一定会比总元素的个数多。那为什么不用数组呢?因为hashtable便于查找。
在这里插入图片描述
//function object 的大小都是0,也有可能编译器会赋予其1。这里的private里面的前两个就是function obJ。
//size_type一般是unsigned int 4个字节。
//这里的node*指针应该指向篮子链表中的结点,这里图画错了。
在这里插入图片描述
//hashtable的数据结构。
7、Unordered container
在这里插入图片描述在这里插入图片描述
//篮子永远大于元素的个数。
//这里这个例子想要放100万个元素进去,但是由于使用的是unordered set,不允许有重复的数据(因为key就是value,所以这里说的是数据),所以实际上放进去的元素只有32768(这个数据也是有原因的,因为使用的随机函数的种子范围是0~32768),然后会发现篮子的个数这里是62233。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值