C++ STL标准库概述--容器

一、定义

STL,英文全称 sdard template library,中文可译为标准模板库或者泛型库,其包含有大量的模板类和模板函数,是 C++ 提供的一个基础模板的集合,用于完成诸如输入/输出、数学计算等功能。简单来讲,STL是一些容器、算法和其他一些组件的集合。

二、组成结构

STL是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成,其中后面 4 部分是为前 2 部分服务的,它们各自的含义如下图所示。

C++ STL标准库概述--容器_第1张图片

C++ 标准中,STL被组织为 13 个头文件。

C++ STL标准库概述--容器_第2张图片

三、容器

容器(container)是用于存放数据的类模板。可变长数组、链表、平衡二叉树等数据结构在 STL 中都被实现为容器。

容器中可以存放基本类型的变量,也可以存放对象。对象或基本类型的变量被插入容器中时,实际插入的是对象或变量的一个复制品。
容器分为两大类,即顺序容器和关联容器;也可以分为三大类:序列容器、排序容器和哈希容器。

1、顺序容器(序列容器)

顺序容器或序列容器,其特点就是元素在容器中的位置同元素的值无关,即容器不会对存储的元素进行排序。将元素插入容器时,指定在什么位置(尾部、头部或中间某处)插入,元素就会位于什么位置。

STL标准库中所有的序列式容器,包括 array、vector、deque、list 和 forward_list。

2、关联容器(排序容器、有序关联容器)

关联容器分为 set(集合)和 map(映射表)两大类,及其衍生体 multiset 和 multimap。这些容器的底层机制均以 RB-tree(红黑树)实现,平衡二叉树中的一种(还包括AVL-tree、AA-tree)。RB-tree 也是一个独立容器,但并不开放使用。

SGI STL 还提供一个不在标准规格的关联式容器 hash_table(散列表),以及以 hash_table 为底层机制而完成的 hash_set散列集合、hash_map散列映射表、hash_multiset散列多键集合、hash_multimap散列多键映射表。

关联容器中每个元素都有一个键值key和一个实值value。关联容器内的元素是排序的。插入元素时,容器会按一定的排序规则将元素放到适当的位置上,因此插入元素时不能指定位置。

默认情况下,关联容器中的元素是从小到大排序(或按关键字从小到大排序)的,而且用`<`运算符比较元素或关键字大小。因为是排好序的,所以关联容器在查找时具有非常好的性能。

3、无序关联容器(哈希容器)


无序关联式容器,它们常被称为“无序容器”、“哈希容器”或者“无序关联容器”。

无序容器是 C++ 11 标准才正式引入到 STL 标准库中的,如果要使用该类容器,则必须选择支持 C++ 11 标准的编译器。

和关联式容器一样,无序容器也使用键值对(pair 类型)的方式存储数据。但是它们有着本质上的不同:关联式容器的底层实现采用的树存储结构,更确切的说是红黑树结构;无序容器的底层实现采用的是哈希表的存储结构。

C++ STL 底层采用哈希表实现无序容器时,会将所有数据存储到一整块连续的内存空间中,并且当数据存储位置发生冲突时,解决方法选用的是“链地址法”(又称“开链法”)。

基于底层实现采用了不同的数据结构,因此和关联式容器相比,无序容器具有以下 2 个特点:
①无序容器内部存储的键值对是无序的,各键值对的存储位置取决于该键值对中的键;
②和关联式容器相比,无序容器擅长通过指定键查找对应的值(平均时间复杂度为 O(1));但对于使用迭代器遍历容器中存储的元素,无序容器的执行效率则不如关联式容器。
和关联式容器一样,无序容器只是一类容器的统称,其包含有 4 个具体容器,分别为 unordered_map、unordered_multimap、unordered_set 以及 unordered_multiset。

这4种无序容器的名称,仅是在关联式容器名称的基础上,添加了 "unordered_"。以 map 和 unordered_map 为例,其实它们仅有一个区别,即 map 容器内存会对存储的键值对进行排序,而 unordered_map 不会。也就是说,C++ 11 标准的 STL 中,在已提供有 4 种关联式容器的基础上,又新增了各自的“unordered”版本(无序版本、哈希版本),提高了查找指定元素的效率。

实际场景中如果涉及大量遍历容器的操作,建议首选关联式容器;反之,如果更多的操作是通过键获取对应的值,则应首选无序容器。

注意,由于哈希容器直到 C++ 11 才被正式纳入 C++ 标准程序库,而在此之前,“民间”流传着 hash_set、hash_multiset、hash_map、hash_multimap 版本,不过该版本只能在某些支持 C++ 11 的编译器下使用(如 VS),有些编译器(如 gcc/g++)是不支持的。

4、容器适配器


除了以上两类容器外,STL 还在两类容器的基础上屏蔽一部分功能,突出或增加另一部分功能,实现了三种容器适配器:栈 stack、队列 queue、优先级队列 priority_queue。

容器适配器是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。

1.  stack:是一个封装了 deque 容器的适配器类模板,默认实现的是一个后入先出(Last-In-First-Out,LIFO)的压入栈。stack 模板定义在头文件 stack 中。
2.  queue:是一个封装了 deque 容器的适配器类模板,默认实现的是一个先入先出(First-In-First-Out,LIFO)的队列。可以为它指定一个符合确定条件的基础容器。queue 模板定义在头文件 queue 中。
3.  priority_queue:是一个封装了 vector 容器的适配器类模板,默认实现的是一个会对元素排序,从而保证最大元素总在队列最前面的队列。priority_queue 模板定义在头文件 queue 中。

适配器类在基础序列容器的基础上实现了一些自己的操作,显然也可以添加一些自己的操作。它们提供的优势是简化了公共接口,而且提高了代码的可读性。

四、成员方法


所有容器都有以下两个成员函数:
①int size():返回容器对象中元素的个数。
②bool empty():判断容器对象是否为空。

顺序容器和关联容器还有以下成员函数:
* begin():返回指向容器中第一个元素的迭代器。
* end():返回指向容器中最后一个元素后面的位置的迭代器。
* rbegin():返回指向容器中最后一个元素的反向迭代器。
* rend():返回指向容器中第一个元素前面的位置的反向迭代器。
* erase(...):从容器中删除一个或几个元素。该函数参数较复杂,此处省略。
* clear():从容器中删除所有元素。

注:如果一个容器是空的,则 begin() 和 end() 的返回值相等,rbegin() 和 rend() 的返回值也相等。

顺序容器还有以下常用成员函数:
* front():返回容器中第一个元素的引用。
* back():返回容器中最后一个元素的引用。
* push_back():在容器末尾增加新元素。
* pop_back():删除容器末尾的元素。
* insert(...):插入一个或多个元素。该函数参数较复杂,此处省略。

总结

以上几种容器的存储方式完全不同,因此使用不同容器完成相同操作的效率也大不相同。所以在实际使用时,要善于根据想实现的功能,选择合适的容器。

你可能感兴趣的:(c算法c++数据结构)