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源码剖析》