1. 组pair
在 C++ STL 中,pair 是其中一个最常用的类型,它位于头文件 <utility> 中。实际上,pair 可以看作是一个单元素的 tuple 类型。pair 将两个值组合在一起,这两个值可以是同一类型或不同类型。pair 的第一个元素可以通过 first 访问,第二个元素可以通过 second 访问。
#include <utility>
using namespace std;
pair <int, int> p1 = { 1, 2 };
cout << p1.first << " " << p1.second << endl;
pair <double, string> p2 = make_pair(1.23, "hello world!");
cout << p2.first << " " << p2.second << endl;
2. 关联容器
与普通数组不同,关联容器中的元素是按一定规则自动排序的。STL 中提供的关联容器包括 set、multiset、map 和 multimap。
2.1 set
set 是一种元素唯一、按照一定规则排序的容器。它的底层实现是二叉搜索树。集合中的元素默认按照小到大的排序规则进行排序。可以通过自定义排序规则来改变元素排序方式,也可以在插入数据时使用自定义类的重载操作符。
#include <set>
using namespace std;
// 通过自定义类的重载操作符
class point {
public:
int x;
int y;
point(int _x, int _y) : x(_x), y(_y) {}
bool operator <(const point &other) const {
if (x != other.x) {
return x < other.x; // 按 x 从小到大排序
} else {
return y < other.y; // 在 x 相同时,按 y 从小到大排序
}
}
};
set <int> s1;
s1.insert(1);
s1.insert(3);
s1.insert(2);
set <point> s2;
s2.insert(point(1, 2));
s2.insert(point(1, 1));
s2.insert(point(2, 1));
2.2 multiset
multiset 也是一种元素唯一、按一定规则排序的容器,它与 set 的区别在于同一个元素在 multiset 中可以有多个副本。也可以用与 set 中相同的方式自定义排序规则。
#include <set>
using namespace std;
multiset <int> s1;
s1.insert(1);
s1.insert(3);
s1.insert(2);
s1.insert(2);
multiset <int>::iterator it = s1.find(2); // 返回一个迭代器,指向包含 2 元素的位置
s1.erase(it); // 将包含 2 元素的位置删除
2.3 map
map 是一种包含有键值对(key-value)的容器,就像一个字典一样。它包含一个 key 值和与其对应的 value 值。key 值可以看作是 map 中元素的索引,所以在 map 中,key 值也是唯一性且有序性的。默认情况下,key 值按照从小到大的顺序进行排序。也可以使用自定义的比较规则来进行排序。
#include <map>
using namespace std;
map <string, int> m1;
m1["aaa"] = 1;
m1["bbb"] = 2;
m1["ccc"] = 3;
map <string, int>::iterator it = m1.find("bbb"); // 返回一个迭代器,指向键值为 "bbb" 的元素所在的位置
m1.erase(it); // 将键值为 "bbb" 的元素删除
2.4 multimap
multimap 与 map 一样,只不过键值可以重复。可以使用与 map 相同的方式查询和操作 multimap 中的数据。
3. 顺序容器
顺序容器中的元素是按插入次序排序的。STL 中提供的顺序容器包括 vector、deque、list。
3.1 vector
vector 是一种动态数组,即封装了大部分 C 数组的相关操作接口,同时支持动态的数组调整。我们可以通过 at、[]、front、back 等方法访问元素。vector 的实现是在连续的存储区域中存储元素。当元素数量超过存储区域的大小后,将会重新分配一块更大的存储区域, 并把原来的元素全部拷贝过去。
#include <vector>
using namespace std;
vector <int> v1;
v1.push_back(10);
v1.push_back(9);
vector <int>::iterator it = v1.begin(); // 返回一个迭代器,指向 vector 的第一个元素
int x = v1.front(); // 返回 vector 的第一个元素
int y = v1[1]; // 返回 vector 的第二个元素
int z = v1.at(1); // 返回 vector 的第二个元素
3.2 deque
deque 也是一种动态数组,与 vector 不同的是,deque 的实现是在多个连续的存储区域中存储元素。deque 支持从两端进行插入和删除操作,可以使用 push_front、push_back、pop_front、pop_back 等方法进行操作。
#include <deque>
using namespace std;
deque <int> d1;
d1.push_back(10);
d1.push_back(9);
d1.push_front(8);
deque <int>::iterator it = d1.begin(); // 返回一个迭代器,指向 deque 的第一个元素
int x = d1.front(); // 返回 deque 的第一个元素
int y = d1.back(); // 返回 deque 的最后一个元素
d1.pop_front(); // 将 deque 的第一个元素弹出
3.3 list
list 是双向链表。它的实现是非连续存储的,每一个元素都包含了前驱和后继指针。在 list 中插入或删除一个元素不会影响链表中其它元素的指针,并且插入或删除操作的时间复杂度为常数级别,而非线性级别。list 不支持随机访问元素,因为没有相关的指针。
#include <list>
using namespace std;
list <int> l1;
l1.push_back(10);
l1.push_back(9);
list <int>::iterator it = l1.begin(); // 返回一个迭代器,指向 list 的第一个元素
int x = l1.front(); // 返回 list 的第一个元素
l1.pop_front(); // 将 list 的第一个元素弹出