STL
STL 是Standard Template Library的缩写,它是C++标准库的一部分,提供了许多常用的数据结构和算法,包括容器、迭代器、算法等。通过使用STL,可以更加方便灵活的处理数据。STL组成如下表。
| 类型 | 功能 |
| 容器 | 一些常用数据结构的模板类 |
| 算法 | 一些常用算法的模板类 |
| 迭代器 | 在STL中,对容器中元素的各种操作通过迭代器完成 |
| 函数对象 | 如果一个类将 () 运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象(又称仿函数) |
| 适配器 | 可以使一个类的接口(模板的参数)适配成用户指定的形式,从而让原本不能在一起工作的两个类工作在一起 |
| 内存分配器 | 为容器类模板提供自定义的内存申请和释放功能 |
迭代器
对于容器的各种操作,都必须使用迭代器完成。迭代器和指针类似,可以指向容器中的任意一个元素,进而对元素进行各种操作。其中STL定义的五种迭代器,如下表。需要注意的是:容器适配器 stack 和 queue 没有迭代器,它们包含有一些成员函数,可以用来对元素进行访问。
| 迭代器类型 | 功能 | 适用容器 |
| 前向迭代器 | 前向迭代器 p 支持 ++p,p++,*p 操作,还可以被复制或赋值,可以用 == 和 != 运算符进行比较 | forward_list |
| 双向迭代器 | 除了支持前向迭代器的所有操作之外,还支持--p 或者 p-- 操作 | list,map,set |
| 随机访问迭代器 | 除了支持前向迭代器的所有操作之外,还支持p+=i,p-=i,p+i,p-i等操作。 | array,vector,deque |
| 输入迭代器 | 输入迭代器可用于读取容器中的元素,但是不保证能支持容器的写入操作 | - |
| 输出迭代器 | 输出迭代器可视为与输入迭代器功能互补的迭代器; 输出迭代器可用于向容器写入元素,但是不保证能支持读取容器内容 | - |
常见的迭代器定义方式有两种:正向迭代器:容器类名::iterator 迭代器名;反向迭代器:容器类名::reverse_iterator 迭代器名。
容器
容器,简单来讲,就是数据结构的一个模板。其中,STL主要有两种容器,序列容器和关联式容器。二者具体的关系如下表。

序列式容器
所谓序列式容器,指的就是用于保存int,char,double等类型数据的,以线性方式排列的的模板。序列容器插入的数据都会插在尾部,所以为了保证删除和插入的时间复杂度,一般都在尾部进行操作。(即数据插入的顺序就是数据保存的顺序)
array<T,N>(数组容器)
数组容器表示可以存储N个T类型的元素,该类容器一旦建立,其长度就是固定不变的,不允许增加和删除元素,只能改变元素的值。
#include<iostream> #include<array> //使用array容器需要array头文件 using namespace std; int main(){ //定义两个array容器 array<int, 5> num_array; array<char, 3> char_array {'a', 'b', 'c'}; //初始化char_array //通过输入来初始化num_array cout << "Initialize the num_array" << endl; for(int i = 0; i < num_array.max_size(); i++){ cin >> num_array[i]; } //使用容器名[]的方式直接访问元素 cout << num_array[0] << endl; cout << char_array[0] << endl; //使用at()函数访问,避免越界访问 cout << num_array.at(0) + num_array.at(2) << endl; // cout << num_array.at(5) << endl; //使用data函数获取首个元素的地址 cout << *(num_array.data()) << endl; cout << *(num_array.data() + 1) <<endl; //使用size函数返回容器中的元素 for(size_t i = 0; i < char_array.size(); i++){ cout << char_array[i] << "\t"; } cout << endl; //使用迭代器返回容器中的元素 for(auto i = num_array.begin(); i < num_array.end(); i++){ cout << *i << "\t"; } return 0; }
vector<T>(向量容器)
用来存放 T 类型的元素,是一个长度可变的序列容器、使用此容器,在尾部增加或删除元素的效率最高。
#include<iostream> #include<vector> using namespace std; int main(void){ vector<int> vector_int; //初始化空的int型vector容器 vector<double> vector_double(5, 1.00); //初始化具有5个初始值为1.0元素的double型vector容器 vector<char> vector_char {'a', 'b', 'c', 'd'}; //初始化含有abcd四个元素的char型vector容器 /*向vector中添加元素的唯一方式是使用vector的成员函数,push_back() & emplace_back()*/ vector_int.push_back(1); vector_int.push_back(2); vector_int.emplace_back(3); vector_int.emplace_back(4); cout << "elements of vector_int are: "; for(auto i = vector_int.begin(); i < vector_int.end(); i++) cout << *i ; cout << endl; /*向vector中插入元素使用Vector的成员函数 insert() & emplace()*/ vector_int.insert(vector_int.begin(), 0); //在vector_int.begin()位置之前插入元素0 vector_int.insert(vector_int.end(), 2, 5); //在vector_int.end()位置之前插入两个元素5 vector_int.insert(vector_int.end(), {6, 7, 8}); //在vector_int.end()位置之前插入6,7,8 cout << "elements of new vector_int are: "; for(int i = 0; i < vector_int.size(); i++) cout << vector_int[i]; cout << endl << endl; /*删除vector中的元素也是使用vector的成员函数*/ cout << "elements of vector_double are: "; for(int i = 0; i < vector_double.size(); i++) cout << vector_double[i]; cout << endl; vector_double.pop_back(); //删除vector_double中的最后一个元素 vector_double.erase(vector_double.begin()); //删除.begin()位置上的元素 cout << "elements of new vector_double are: "; for(int i = 0; i < vector_double.size(); i++) cout << vector_double[i]; /*capacity指给当前所能容纳最大元素数,size指当前容器实际容纳元素数*/ cout << endl << "vector_double.capacity: " <<vector_double.capacity() << endl; cout << "vector_double.size: " << vector_double.size() << endl << endl; /*swap函数可以交换任意两个容器的元素*/ swap(*(vector_char.begin()), *(vector_char.end()-1));//交换第一个和第四个元素 cout << vector_char.size(); cout << "vector_char: "; for(auto i = vector_char.begin(); i < vector_char.end(); i++) cout << *i; cout << endl; vector<char> new_vector_char; new_vector_char.swap(vector_char); cout << "elements of new_vector_char are: "; for(auto && i : new_vector_char) cout << i; cout << endl; return 0; }

deque<T>(双端队列容器)
使用该容器不仅尾部插入和删除元素高效,在头部插入或删除元素也同样高效,时间复杂度都是 O(1) 常数阶。
#include<iostream> #include<deque> using namespace std; int main(void){ deque<int> deque_int; //初始化空的int型双端队列 deque<double> deque_double(5, 2.0); //初始化有5个元素初值为2.0的双端队列 deque<char> deque_char {'a', 'b', 'c', 'd'}; //初始化有abcd的双端队列 /*对deque_int进行赋初值的操作*/ deque_int.push_front(0); //在头部添加元素0 deque_int.push_front(1); //在头部添加元素1 deque_int.push_back(2); //在尾部添加元素2 deque_int.push_back(3); //在尾部添加元素3 deque_int.emplace_front(5); //在头部添加元素5 deque_int.emplace_back(6); //在尾部添加元素6 cout << "elements of deque_int are: "; for(auto i = deque_int.begin(); i < deque_int.end(); i++) cout << *i; cout << endl << endl; cout << "elements of deque_double are: "; for(int i = 0; i < deque_double.size(); i++) cout << deque_double[i]; cout << endl; deque_double.insert(deque_double.begin()+1, 3.1);//在第二个位置之前插入元素3.1 deque_double.emplace(deque_double.end()-1, 4.5); //在最后一个元素之前位置插入4.5 cout << "elements of altering deque_double are: "; for (auto i = deque_double.begin(); i < deque_double.end(); i++) { cout << *i << " "; } cout << endl << endl; cout << "elements of deque_char are: "; for(int i = 0; i < deque_char.size(); i++) cout << deque_char[i]; cout << endl; deque_char.pop_back(); //删除最后一个元素 deque_char.pop_front(); //删除头一个元素 deque_char.erase(deque_char.begin()); //删除指定位置的元素 cout << "elements of altering deque_char are: "; for(auto i = deque_char.begin(); i < deque_char.end(); i++) cout << *i; cout << endl << endl; return 0; }

list<T>(链表容器)
该容器是一个长度可变的、由 T 类型元素组成的序列,它以双向链表的形式组织元素,可以增删任意一个元素,但是访问元素必须在链头或链尾开始。
#include<iostream> #include<list> using namespace std; int main(void){ list<int> list_int; //初始化空的int型list容器 list<double> list_double(5, 1.00); //初始化具有5个初始值为1.0元素的double型list容器 list<char> list_char {'a', 'b', 'c', 'd'}; //初始化含有abcd四个元素的char型list容器 /*向list_int中插入元素*/ list_int.push_front(0); //在头部添加元素0 list_int.push_front(1); //在头部添加元素1 list_int.push_back(2); //在尾部添加元素2 list_int.push_back(3); //在尾部添加元素3 list_int.emplace_front(5); //在头部添加元素5 list_int.emplace_back(6); //在尾部添加元素6 cout << "elements of list_int are: "; for(auto i = list_int.begin(); i != list_int.end(); i++) cout << *i; cout << endl << endl; /*向list_double中插入元素*/ cout << "elements of list_double are: "; for (auto i = list_double.begin(); i != list_double.end(); i++) { cout << *i << " "; } cout << endl; list_double.insert(list_double.begin(), 3.1);//在第二个位置之前插入元素3.1 list_double.emplace(list_double.end(), 4.5); //在最后一个元素之前位置插入4.5 cout << "elements of altering list_double are: "; for (auto i = list_double.begin(); i != list_double.end(); i++) { cout << *i << " "; } cout << endl << endl; /**/ cout << "elements of list_char are: "; for(auto i = list_char.begin(); i != list_char.end(); i++) cout << *i; cout << endl; list_char.pop_back(); //删除最后一个元素 list_char.pop_front(); //删除头一个元素 list_char.erase(list_char.begin()); //删除指定位置的元素 list_char.insert(list_char.begin(), 3, 'e'); //插入三个相同的元素e list_char.remove('e'); //删除所有e cout << "elements of altering list_char are: "; for(auto i = list_char.begin(); i != list_char.end(); i++) cout << *i; cout << endl << endl; return 0; }
forward_list<T>(正向链表容器)
该容器和 list 容器非常类似,只不过它以单链表的形式组织元素,它内部的元素只能从第一个元素开始访问。
#include<iostream> #include<forward_list> using namespace std; int main(void){ forward_list<int> forward_list_int; //初始化空的int型forward_list容器 forward_list<char> forward_list_char {'a', 'b', 'c', 'd'}; //初始化含有abcd四个元素的char型forward_list容器 forward_list_int.push_front(0); //在头部添加元素0 forward_list_int.push_front(1); //在头部添加元素1 forward_list_int.emplace_front(2); //在头部添加元素2 forward_list_int.emplace_front(3); //在头部添加元素3 for(auto i = forward_list_int.begin(); i != forward_list_int.end(); i++) cout << *i; cout << endl << endl; cout << "elements of forward_list_char are: "; for(auto i = forward_list_char.begin(); i != forward_list_char.end(); i++) cout << *i; cout << endl; forward_list_char.pop_front(); //删除头部元素 auto it = forward_list_char.begin(); while (it!=forward_list_char.end()) { cout << *it; ++it; } return 0; }
关联式容器
关联式容器在存储元素的值的同时,还会为每一个元素配备一个额外的值,又称之键“ key ”。关联式容器的优点在于只要知道某一个元素的键,就可以直接通过该键的值直接找到目标元素,而无需遍历整个容器。即关联式容器按照<key, value>的方式存储元素。序列式容器按照元素输入顺序存储元素。
pair类模板:C++ STL提供了pair类模板将两个元素组合成<key, value>类型的元素。
#include<iostream> #include<utility> #include<string> using namespace std; int main(void){ pair <string, string> pair1("key", "value"); pair <string, string> pair2("key2", "value2"); cout << "pair1: " << pair1.first << " " << pair1.second << endl; cout << "pair2: " << pair2.first << " " << pair2.second << endl; return 0; }
map
一般情况下,map容器中存储的各个键值对都选用string字符串作为键的类型。在使用map容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。默认根据键值大小做升序排序。
set
multimap
multiset
算法
参考资料
[1] STL,C语言中文网,http://c.biancheng.net/stl/。



浙公网安备 33010602011771号