您的位置:首页 > 编程语言

STL源代码剖析个人小结3--STL容器

2012-08-30 17:22 260 查看
STL中的容器有两类: 序列式容器和关联式容器

一. 序列式容器: 指其中的元素可以有序也可以无序。常用的标准序列式容器如下:

1. vector

相比与C++内置的静态数组array,vector则代表着动态空间,随着元素的加入其内部机制回自行扩充空间以容纳新元素。担当元素删除时岂不会自动释放空间。

当容器已满在进行插入操作时,vector会首先申请另外一块更大的空间(通常是目前空间的两倍),然后将元素前移至新空间,最后释放原来的空间。因而其实现技术的关键在于对容器大小的控制及空间重新配置时数据的移动效率。

因插入操作可能会引起空间的重新配置,故可能会导致全部的迭代器失效。

<1>.heap 不是STL的标准容器组件,其是以vector作为底层,以二叉堆作为数据结构进行组织的一个容器。其很少单独使用,其往往充当priority queue的幕后助手。二叉堆本质上就是符合堆性质(大顶堆或小顶堆)的的完全二叉树。其实完全可以采用平衡二叉树或者红黑树进行组织,但是因heap只需要快速输出最大(最小)元素又不要求排序故堆已完全能够满足要求,就没有必要使用平衡二叉树或红黑树了(维护比较费事)。

<2>priority queue 优先级队列 ,非STL的标准容器。以heap为基础构建的。

2.list

list为双向循环链表。优点:每次插入或者删除一个元素,就配置或者释放一个元素的空间;空间利用率高。且对于任何位置的插入删除操作时间复杂度都可以达到常数级别。而且插入删除操作只会使本身迭代器失效,而其它迭代器不会失效。但是因为list的迭代器类型为Bidrection而STL 中的sort算法要求迭代器类型为Random Access,故list容器无法使用STL的sort算法,只能使用容器本身的排序算法。

<1>slist : list的一个容器配接器,单向链表。其并非STL标准容器。其前插操作较难实现,故容器本身提供了响应的后插操作作为替代。

3.deque

deque与vector的不同之处:deque可以在常数时间内在头端进行元素插入或者删除,此容器无容量的概念。其空间的配置以缓冲区为单位,当头(或者尾)端缓冲区内空间已耗尽则另外申请一缓冲区放于头端(或者尾端)来存数数据。且当删除元素导致头端(或者尾端)的缓冲区为空时可以自动释放此缓冲,以提高空间利用率。缓冲区默认大小事512b,可以手工设定缓冲区的大小。

难点:因deque底层空间是由多个缓冲区块组合而成的,并非像vector那样是一整个连续的区块,那么如何通过迭代器使分段连续的线性空间以连续空间的外貌呈献给使用着呢? deque采用了两层迭代器结构,其中map作为主控节点,其每个节点都是一个复合迭代器,而每个复合迭代器都指向一段连续的线性空间。(具体描述待补充。。。)

<1>stack: deque的一个配接器 即常用的堆栈

<2>queue: deque的一个配接器 即常用的单向队列

注意:上述所有配接器都不含迭代器

二. 关联式容器

1. RB-tree: 是set及map的底层结构。其是一个高级的二叉排序树。具有五个特点:节点要么为黑要么为红,根节点为黑,叶子节点为黑,红节点的孩子为黑,从根节点往下遍历到每个叶子节点所经过的黑节点个数相同。这五个特定在一定程度上保证了二叉排序树的平衡性。

set,multiset,map,multimap中元素都是有序的。

2.hash table::关联容器中以哈希为底层的都不具有自动排序的功能,且其不被STL算法中的集合运算所支持。以RB-tree为底层的集合每个操作的复杂度为对数时间,而以Hash table为底层的关联式容器其复杂度为常数时间(理论上为o(1)),但这是以大量空间小号为代价的,且元素无序。

Hash : 三个问题:

<1> 用Hash函数解决了空间太大的问题(通过hash映射)

<2>. 通过对键值编码解决了非数值键值无法进行映射的问题

<3>. 冲突解决

线性探测法---容易造成主聚簇

二次探测法---容易造成次聚簇

复式散列法---过于复杂

开链法-----Hash表的负载系数可能大于1,但比较方便。SGI STL 版本的Hash table便是采用此种方案

目前hash_set,hash_map,hash_multiset,hash_multimap都已经被STL吸纳为了标准。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: