Loading

C++ STL 系列——基本概念

一、STL 基本组成

通常认为,STL 是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成,其中后面 4 部分是为前 2 部分服务的。

STL 的组成 含义
容器 一些封装数据结构的模板类,例如 vector 向量容器、list 列表容器等。
算法 STL 提供了非常多(大约 100 个)的数据结构算法,它们都被设计成一个个的模板函数,这些算法在 std 命名空间中定义,其中大部
分算法都包含在头文件 中,少部分位于头文件 中。
迭代器 在 C++ STL 中,对容器中数据的读和写,是通过迭代器完成的,扮演着容器和算法之间的胶合剂。
函数对象 如果一个类将 () 运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象(又称仿函数)。
适配器 可以使一个类的接口(模板的参数)适配成用户指定的形式,从而让原本不能在一起工作的两个类工作在一起。值得一提的是,容器、迭代器和函数都有适配器。
内存分配器 为容器类模板提供自定义的内存申请和释放功能,由于往往只有高级用户才有改变内存分配策略的需求,因此内存分配器对于一般用户来说,并不常用。

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

<iterator>、<functional>、<vector>、<deque>
<list>、<queue>、<stack>、<set>
<map>、<algorithm>、<numeric>、<memory>
<utility>

二、什么是容器

简单的理解容器,它就是一些模板类的集合,但和普通模板类不同的是,容器中封装的是组织数据的方法(也就是数据结构)。STL 提
供有 3 类标准容器,分别是序列容器、排序容器和哈希容器,其中后两类容器有时也统称为关联容器。

容器种类 功能
序列容器 主要包括 vector 向量容器、list 列表容器以及 deque 双端队列容器。之所以被称为序列容器,是因为元素在容器中的位置同元素的值无关,即容器不是排序的。将元素插入容器时,指定在什么位置,元素就会位于什么位置。
排序容器 包括 set 集合容器、multiset 多重集合容器、map 映射容器以及 multimap 多重映射容器。排序容器中的元素默认是由小到大排序好的,即便是插入元素,元素也会插入到适当位置。所以关联容器在查找时具有非常好的性能。
哈希容器 C++ 11 新加入 4 种关联式容器,分别是 unordered_set 哈希集合、unordered_multiset 哈希多重集合、unordered_map 哈希映射以及 unordered_multimap 哈希多重映射。和排序容器不同,哈希容器中的元素是未排序的,元素的位置由哈希函数确定。

三、STL 迭代器

迭代器可以是需要的任意类型,通过迭代器可以指向容器中的某个元素,除了具有对容器进行遍历读写数据的能力之外,还能对外隐藏容器的内部差异。

迭代器类别

常用的迭代器按功能强弱分为输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器。

  • 输入/输出迭代器是把输入/输出流作为操作对象;
  • 前向(正向)迭代器支持往后移动,还可以被复制或赋值。此外两个正向迭代器可以互相赋值;
  • 双向迭代器既能向前也能向后移动,具有正向迭代器的全部功能;
  • 随机访问迭代器具有双向迭代器的全部功能,此外还能以当前位置为基准随机访问第 i 个元素或返回第 i 个元素的迭代器。此外两个随机访问迭代器还可以用 > 、< 运算符进行比较

不同容器的迭代器

容器 对应的迭代器类型
array 随机访问迭代器
vector 随机访问迭代器
deque 随机访问迭代器
list 双向迭代器
set/multiset 双向迭代器
map/multimap 双向迭代器
forward_list 前向迭代器
unordered_map/unordered_multimap 前向迭代器
unordered/unordered_multiset 前向迭代器
stack 不支持迭代器
queue 不支持迭代器

迭代器的定义方式

尽管不同容器对应着不同类别迭代器,但这些迭代器有着较为统一的定义方式,具体分为 4 种:

迭代器定义方式 具体格式
正向迭代器 容器类名::iterator 迭代器名
常量正向迭代器 容器类名::const_iterator 迭代器名
反向迭代器 容器类名::reverse_iterator 迭代器名
常量反向迭代器 容器类名::const_reverse_iterator 迭代器名
  • 对正向迭代器进行 ++ 操作时,迭代器会指向容器中的后一个元素;
  • 对反向迭代器进行 ++ 操作时,迭代器会指向容器中的前一个元素。
  • 以上 4 种定义迭代器的方式,不是每个容器都适用。
#include <vector>

int main(){
    vector<int> v{1,2,3,4,5,6,7,8,9};
    vector<int>::iterator i;
    for( i=v.begin(); i!= v.end(); ++i)
        cout << *i << " ";

    for(i=v.begin(); i<v.end();>){
        cout << *i << " ";
        i += 2;     // 随机访问迭代器,支持 <,[], += 等操作
    }
}

再举一个例子, list 容器的迭代器是双向迭代器,那么它能进行的操作和 vector 就会不一样。

list<int> v;

list<int>::const_iterator i;

for( i = v.begin(); i!= v.end(); ++i)  
   cout << *i;

// 错误,双向迭代器不支持 <
for( i = v.begin();i<v.end(); ++i )
    cout << *i;

// 错误,双向迭代器不支持下标随机访问
for(int i = 0; i <v.size; i++)
    cout << v[i];
posted @ 2021-11-06 10:30  锦瑟,无端  阅读(133)  评论(0编辑  收藏  举报