一、基本概念
STL分为三部分:算法、容器、迭代器。C++中的STL主要有以下头文件:
#include <algorithm>
#include <deque>
#include <functional>
#include <iterator>
#include <vector>
#include <list>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <stack>
二、容器
1.分类
容器分为两类:序列式容器和关联式容器。
序列式容器:每个元素都有固定的位置,取决于插入元素的时机和地点,与元素值无关。
例如:vector、deque、list、queue、stack。
关联式容器:元素位置取决于特定的排序规则,与插入元素顺序无关。
例如:set、mulitset、map、mutilmap
2.介绍
- 向量(vector):连续存储的元素。头文件<vector>。
- 列表(list):由节点组成的双向链表,每个节点包含一个元素。头文件<list>。
- 双队列(deque):连续存储的指向不同元素的指针所组成的数组。头文件<deque>。
- 集合(set):由节点组成的红黑树,每个节点包含一个元素,节点之间由某种作用于元素的谓词排列,没有两个不同的元素能够拥有相同的次序(set中不存在相同的元素,可以去重)。头文件<set>。
3.vector
一个动态数组,在尾部加入或删除元素较快,在中部和头部相对较慢。
3.1 vector的构造
int main() {
// vector
// 1. vector的默认构造
vector<int> vec;
// 2. vector的带参构造
int array[] = { 1,2,3,4,5 };
vector<int> v1(array, array + 5); // 左闭右开,把数组array复制给v1
vector<int> v2(4, 10); // 存储3个10
vector<int> v3(v2); // 拷贝构造,参数是另一个vector的引用,就是用一个构造好的vector去初始化另一个vector
vector<int> v4 = v2;
}
3.2 vector元素赋值
这里用到了assign()、swap()函数和运算符重载三种方式。
int main() {
// vector元素赋值
// 1. assign:会清空原vector
vector<int> vecA, vecB, vecC, vecD, vecE;
int array[] = { 1,2,3,4,5,6 };
vecA.assign(array, array + 6); // 左闭右开
vecB.assign(5, 10); // 存放5个10
vecC.assign(vecA.begin(), vecA.end()); // vecA.begin()是vecA中的第一个元素地址,vecA.end()是vecA中的最后一个元素地址
// 2. swap()函数:互换两个vector的值
vecD.swap(vecC);
// 3. 利用重载运算符
vecE = vecA;
}
3.3 vector的大小
这里主要介绍几个函数:
- vector.size():返回vector的长度
- vector.empty():判断是否为空
- vector.resize():重新定义vector的长度,若边长,就用默认值填充;若变短,就删除末尾元素。
- vector.resize(int num, class elem):重新定义vector的长度,若边长,用elem填充。
int main() {
// vector元素的大小
// 1. size() empty()
vector<int> vecA, vecB, vecC;
int array[] = { 1,2,3,4,5,6 };
vecA.assign(array, array+6);
cout << "vecA size:" << vecA.size() << endl;
cout << "vecA is empty? " << vecA.empty() << endl;
// 2. resize(int) resize(int , class)
vecB = vecA;
vecB.resize(10);
vecC = vecA;
vecC.resize(10, 99);
for (int i = 0; i < vecB.size(); i++) {
cout << vecB.at(i) << " ";
}
cout << endl;
for (int i = 0; i < vecC.size(); i++) {
cout << vecC.at(i) << " ";
}
}
3.4 vector访问元素
用下标的方式访问:vec[index],如果下标越界,程序会异常终止。
使用at(index)函数,越界的话会抛出一个异常。
// vector访问元素
// at(index) 函数
int array[] = { 1,2,3,4,5 };
vector<int> vec(array, array + 5);
cout << vec.at(4);
3.5 vector插入元素
我们可以在vector的任意位置添加或删除元素
- 在末尾添加元素push_buck(elem)
- 在末尾删除元素pop_back()
- 在中间位置添加元素:vector.insert()
// vector插入元素
int array[] = { 1,2,3,4,5,6 };
vector<int> vecA(array, array + 6), vecB(array, array + 6), vecC(array, array + 6), vecD(array, array + 6), vecE(array, array + 6);
// 1. 在末尾添加元素push_back(elem)
vecA.push_back(7);
for (int i = 0; i < vecA.size(); i++) {
cout << vecA.at(i) << " ";
}
cout << endl;
// 2. 在末尾删除元素
vecB.pop_back();
for (int i = 0; i < vecB.size(); i++) {
cout << vecB.at(i) << " ";
}
cout << endl;
/*3. 在中间添加元素insert()
3.1 insert(pos, elem):在pos位置处插入元素elem,并返回位置
3.2 insert(pos, n, elem):在pos位置处插入n和元素elem,无返回值
3.3 insert(pos, begin, end):在pos处插入[begin, end)的元素,无返回值
vec: {1,2,3,4,5,6}
*/
vecC.insert(vecC.begin()+2, 100);
vecD.insert(vecD.begin() + 2, 10, 100);
vecE.insert(vecE.begin() + 2, array + 3, array + 5);
for (int i = 0; i < vecC.size(); i++) {
cout << vecC.at(i) << " ";
}
cout << endl;
for (int i = 0; i < vecD.size(); i++) {
cout << vecD.at(i) << " ";
}
cout << endl;
for (int i = 0; i < vecE.size(); i++) {
cout << vecE.at(i) << " ";
}
cout << endl;
4.迭代器
4.1 概念
迭代器是一种检查容器内元素并遍历元素的数据类型。迭代器的作用是提供对一个容器中对象的访问方法,并且定义了容器中对象的范围。
使用迭代器去访问元素,不用[index]方法,也不要.at()函数。
4.2 为什么要用到迭代器?
- STL中各种容器的实现原理不同,访问元素方式也不同,很麻烦。而每个容器都实现了一个迭代器用于对元素的访问。
- 像使用指针遍历的话,只能一个一个移动。而迭代器可以一次移动多个位置,效率要好一些。
4.3 使用
int array[] = { 1,2,3,4,5,6 };
vector<int> vecIntA(array, array + 6), vecIntB;
// 构造一个迭代器对象
vector<int>::iterator iter;
/*
1. 用迭代器it指向容器中的第一个元素;begin()函数,这个iter本质上就是一个指针
*/
iter = vecIntA.begin();
cout << *iter << endl;
/*
2. 通过循环的方式 使用迭代器遍历元素
*/
for (vector<int>::iterator it = vecIntA.begin(); it < vecIntA.end(); it++) {
cout << *it << " ";
}
cout << '\n';
/*
iter的加减
*/
iter = vecIntA.begin();
cout << *(iter + 2) << " " << *(iter + 1) << endl;
4.4 迭代器的失效
// 迭代器的失效
int array[] = { 1,2,3,4,5 };
vector<int> vecIntA(array, array + 5);
vector<int>::iterator iter = vecIntA.begin() + 4;
cout << *iter << endl;
4.4.1 insert
在以上代码基础上,在vector中新增或删除一个元素,这时迭代器会失效。
vecIntA.insert(iter-1, 100);
因为会把原有内存被释放掉,再去开辟一个新的内存存放元素,原iter成为一个野指针。但是不要慌,insert函数会返回一个新的迭代器newIt,newIt指向了新的vector内存空间中保存新增元素的那个地址。
int array[] = { 1,2,3,4,5 };
vector<int> vecIntA(array, array + 5);
vector<int>::iterator iter = vecIntA.begin() + 4;
cout << *iter << endl;
// insert会返回一个新的有效的迭代器
vector<int>::iterator newIt = vecIntA.insert(iter-1, 100);
cout << *newIt << endl;
4.4.2 erase
删除vector中的元素也会导致迭代器失效,有如下vector:
// 迭代器的失效:erase
vector<int> vecIntA = { 1,2,3,3,3,3,3,4,5 };
vector<int>::iterator iter = vecIntA.begin();
现在要将容器中的3全部删除,则以下代码不行:
for (vector<int>::iterator it = vecIntA.begin(); it < vecIntA.end();) {
if (*it == 3) {
vecIntA.erase(it);
}
else
{
it++;
}
}
这是因为迭代器在执行一次erase后会失效,但erase函数会返回一个新迭代器,与insert相同。
以下代码正确:
for (vector<int>::iterator it = vecIntA.begin(); it < vecIntA.end();) {
if (*it == 3) {
it = vecIntA.erase(it);
}
else
{
it++;
}
}