STL源码分析:Containers

STL容器分两种:序列式容器,关联式容器。

上图以内缩方式来表达基层与衍生层的关系。

heap内含一个vector,priority-queue内含一个heap、stack和queue都含一个deque,set/map/multiset/multimap都内含一个RB-tree,hash_x都内含一个hastable。

序列式容器

所谓序列式容器,其中的元素都可序(ordered),但未必有序(sorted)。C++语言本身提供了一个序列式容器array。STL另外再提供 上列呈现的序列式容器。

vector

vector的数据安排以及操作方式与array非常相似。两者唯一差别在于空间的运用的灵活性上。array是静态空间,设定要先定义空间。vector是动态空间,它的内部机制会自行扩充空间以容纳新元素。vector人运用对于内存的合理利用与运用的灵活性有很大的帮助。

vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率。这里具体要看空间配置的策略。

vector的数据结构:线性连续空间。它以两个迭代器start和finish分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器end_of_storage指向整块连续空间(含备用空间)的尾端。为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求量更大一些,以备将来可能的扩充。这便是容量(capacity)的观念。

vector的迭代器:因为普通指针就可以满足vector的所有必要条件,而vector支持随机存取,所以vector提供的是Random Access Iterators。

list

list的好处是每次插入或删除一个元素,就配置或释放一个元素空间。list对于空间的运用有绝对的精准,一点也不浪费。而且对于任何位置的元素插入或无素移除,list永远是常数时间。

list和vector的选择最多视所元素的多寡、元素的构造复杂度、元素存取行为的特性而定。

list的数据结构:从list的节点结构看,STL中的list是个双向链表。

list的迭代器:所其操作上看,其迭代器是Bidirectional Itertors。

deque

vector是单向开口的连续线性空间,deque则是一种双向开口的连续线性空间。

deque没有容量观念。不像vector那样“因旧空间不足而重新配置一块更大空间,然后复制元素,再释放旧空间”。

deque的数据结构:array无法成长,vector虽可成长,却只能向尾端成长,而且是个假象。deque采用一块“map”作缓冲区,利用这个map成长。

deque的迭代器:和vector相似,是Random Access Iterators。

stack与queue

这两种都没有迭代器,数据结构是用deque实现的(其实用list也可以)。

heap

heap不归属于stl容器组件,它是priority queue的助手。priority queue允许用户以任何次序将任何元素推入容器内,但取出时一定是从优先权最高(也就是数值最高)的元素开始取。binary max heap正是具有这样的特性,适合作为priority queue的底层机制。

heap底部容器:以vector表现的完全二叉树。

实现算法:最大堆。

priority_queue

priority_queue是一个拥有权值观念的queue。

priority_queue没有迭代器。

slist

这是个单向链表,所以迭代器变为Forward Iterator。

关联式容器

标准的STL关联式容器分为set(集合)和map(映射表)两大类,以及这两大类的衍生体mutiset(多键集合)和multimap(多键映射表)。这些容器的底层机制均以RB-tree(红黑树)完成。RB-tree也是一个独立容器,但并不开放给外界使用。

此外,STL还提供了一个关联式容器:hash_table(散列表),以及以此为底层机制而完成的hash_set(散列集合)、hash_map(散列映射表)、hash_multiset(散列多键集合)、hash_multimap(散列多键映射表)。

所谓关联式容器,观念上类似关联式数据库(key-value)。当元素被插入到关联式容器中时,容器内部结构(可能是RB-tree,也可能是hash-table)便依照其键值大小,以某种特定规则将这个元素放置于适当位置。

关联式容器没有所谓头尾(只有最大元素与最小元素)。

一般而言,关联式容器的内部结构是一个balanced binary tree,以便获得良好的搜寻效率。

set

set的特性是所有元素都会根据元素的键值自动被排序。set元素的键值就是实值,实值就是健值。set不允许两个元素有相同的键值。

map

map的特性是,所有元素都会根据元素的键值自动被排序。map的所有元素都是pair。

multiset与multimap

特性以及用法和各自兄弟(set,map)完全相同,唯一的差别在于它们允许键值重复。

hashtable

二叉搜索树表现的构造在一个假设上:输入数据有足够的随机性。而hash_table(散列表)的数据结构的操作表现是以统计为基础,不需仰赖输入元素的随机性。

hash_set、hash_map、hash_multiset、hash_multimap

都是以hash_table为底层机制。但其实元素不能自动排序。

参考:《STL源码剖析》

猜你喜欢

转载自www.cnblogs.com/losophy/p/9494488.html