STL指南
常见 STL
容器及使用。
STL 容器
C++ 库以提供“模板”为主。模板是指不必预先制定类型的函数或类。我们可以借助STL(标准模板库 Standard Template Library, STL)提供的高效算法来管理数据。为应对多种需求,STL 为用户提供了多种名为容器(Container)的类,用于管理数据集合。在创建动态数组、表、栈、队列等数据结构时,我们只需要定义对应的容器,然后调用相应成员函数或算法即可。
在C++标准中,STL被组织为下面的13个头文件:<algorithm>
、<deque>
、<functional>
、<iterator>
、<vector>
、<list>
、<map>
、<memory.h>
、<numeric>
、<queue>
、<set>
、<stack>
、<utility>
。
STL可分为容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分。
1. 基础
1.1. string(字符串)
1.1.1. 介绍
要使用 string
类,必须包含头文件 <string>
。string
库提供了许多其他功能,如删除字符串的部分或全部,用一个字符的部分或全部替换另一个字符串的部分或全部,插入、删除字符串中数据,比较、提取、复制、交换等。
1.1.2. 函数
https://zh.cppreference.com/w/cpp/string/basic_string
1.1.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "1234567";
char ch[] = "abcdefg";
// 构造字符串
string str0("ABCDEFG"); // 定义一个字符串
string str1(str); // 构造函数,全部复制
string str2(str, 2, 5); // 构造函数,从字符串str的第2个元素开始,复制5个元素,赋值给str_2
string str3(ch, 5); // 将字符串ch的前5个元素赋值给str_3
string str4(5, 'X'); // 将 5 个 'X' 组成的字符串 "XXXXX" 赋值给 str_4
string str5(str.begin(), str.end()); // 复制字符串 str 的所有元素,并赋值给 str_5
cout << str << endl;
cout << str0 << endl;
cout << str1 << endl;
cout << str2 << endl;
cout << str3 << endl;
cout << str4 << endl;
cout << str5 << endl;
// 获取长度
int size = 0;
int length = 0;
long maxsize = 0;
int capacity = 0;
string str_custom = str;
str_custom.resize(5);
size = str_custom.size();
length = str_custom.length();
maxsize = str_custom.max_size();
capacity = str_custom.capacity();
cout << "size = " << size << endl;
cout << "length = " << length << endl;
cout << "maxsize = " << maxsize << endl;
cout << "capacity = " << capacity << endl;
// 获取字符
char temp;
char temp_1;
temp = str[2]; //"获取字符 'c'
temp_1 = str.at(2); //获取字符 'c'
cout << temp << " " << temp_1 << endl;
// 查找
string x("Hi, Peter, I'm sick. Please bought some drugs for me.");
int p = x.find('P');
int rp = x.rfind('P');
cout << "find() 查找的P在第 " << p << " 位" << endl;
cout << "rfind()查找的P在第 " << rp << " 位" << endl;
int q = x.find("some", 0);
int rq = x.rfind("some", 0);
cout << "find() 查找的some在第 " << q << " 位" << endl;
cout << "rfind()查找的some在第 " << rq << " 位" << endl;
int l = x.find(" drugs", 0, 5);
int rl = x.rfind(" drugs", 0, 5);
cout << "find() 查找的' drugs'在第 " << l << " 位" << endl;
cout << "rfind()查找的' drugs'在第 " << rl << " 位" << endl;
string y("sick");
int m = x.find(y, 0);
int rm = x.rfind(y, 0);
cout << "find() 查找的y字符串在第 " << m << " 位" << endl;
cout << "rfind()查找的y字符串在第 " << rm << " 位" << endl;
return 0;
}
2. 序列式容器
2.1. vector
2.1.1. 介绍
需要包含头文件 <vector>
,vector
是一个能够存放任意类型的动态数组,能够增加和压缩数据。
2.1.2. 函数
https://zh.cppreference.com/w/cpp/container/vector
2.1.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <vector>
using namespace std;
/**
* 遍历方式
* 1. 通过数组下标遍历
* 2. 通过迭代器遍历
* 3. C++11标准,auto关键字遍历
*/
void display1(vector<string> wordDict) {
for (int i = 0; i < wordDict.size(); i++) {
cout << wordDict[i] << " ";
}
cout << endl;
}
void display2(vector<string> wordDict) {
vector<string>::iterator item = wordDict.begin();
for (; item != wordDict.end(); item++) {
cout << *item << " ";
}
cout << endl;
}
void display3(vector<string> wordDict) {
for (auto i : wordDict) {
cout << i << " ";
}
}
/**
* 序列式容器: 向量(vector) 连续存储的元素 <vector>
*/
int main() {
vector<string> wordDict = {"cat", "cats", "and", "sand", "dog"};
display1(wordDict);
display2(wordDict);
display3(wordDict);
return 0;
}
2.2. list(链表)
2.2.1. 介绍
需要包含头文件 <list>
,list
将元素按顺序储存在链表中与 vectors
相比, 它允许快速的插入和删除,但是随机访问却比较慢。
2.2.2. 函数
https://zh.cppreference.com/w/cpp/container/list
2.2.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
#include <list>
#include <vector>
using namespace std;
//从前向后显示list队列的全部元素
void put_list(list<int> List, char* name) {
list<int>::iterator plist;
cout << "The contents of " << name << " : ";
for (plist = List.begin(); plist != List.end(); plist++) {
cout << *plist << " ";
}
cout << endl;
}
//测试list容器的功能
int main() {
//list1对象初始为空
list<int> list1;
char* list1_name = (char*)"list1";
//list2对象最初有10个值为6的元素
list<int> list2(10, 6);
char* list2_name = (char*)"list2";
//list3对象最初有3个元素
vector<int> nums = {1, 2, 3, 4, 5, 6};
list<int> list3(nums.begin(), nums.begin() + 3);
char* list3_name = (char*)"list3";
//声明一个名为i的双向迭代器
list<int>::iterator i;
//从前向后显示各list对象的元素
put_list(list1, list1_name);
put_list(list2, list2_name);
put_list(list3, list3_name);
//从list1序列后面添加两个元素
list1.push_back(2);
list1.push_back(4);
cout << "list1.push_back(2) and list1.push_back(4):" << endl;
put_list(list1, list1_name);
//从list1序列前面添加两个元素
list1.push_front(5);
list1.push_front(7);
cout << "list1.push_front(5) and list1.push_front(7):" << endl;
put_list(list1, list1_name);
//在list1序列中间插入数据
list1.insert(++list1.begin(), 3, 9);
cout << "list1.insert(list1.begin()+1,3,9):" << endl;
put_list(list1, list1_name);
//测试引用类函数
cout << "list1.front()=" << list1.front() << endl;
cout << "list1.back()=" << list1.back() << endl;
//从list1序列的前后各移去一个元素
list1.pop_front();
list1.pop_back();
cout << "list1.pop_front() and list1.pop_back():" << endl;
put_list(list1, list1_name);
//清除list1中的第2个元素
list1.erase(++list1.begin());
cout << "list1.erase(++list1.begin()):" << endl;
put_list(list1, list1_name);
//对list2赋值并显示
list2.assign(8, 1);
cout << "list2.assign(8,1):" << endl;
put_list(list2, list2_name);
//显示序列的状态信息
cout << "list1.max_size(): " << list1.max_size() << endl;
cout << "list1.size(): " << list1.size() << endl;
cout << "list1.empty(): " << list1.empty() << endl;
//list序列容器的运算
put_list(list1, list1_name);
put_list(list3, list3_name);
cout << "list1>list3: " << (list1 > list3) << endl;
cout << "list1<list3: " << (list1 < list3) << endl;
//对list1容器排序
list1.sort();
put_list(list1, list1_name);
//结合处理
list1.splice(++list1.begin(), list3);
put_list(list1, list1_name);
put_list(list3, list3_name);
return 0;
}
2.3. deque(双端队列)
2.3.1. 介绍
需要包含头文件 <deque>
deque
容器和 vecotr
容器相同处:
deque
容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)
),而不擅长在序列中间添加或删除元素。deque
容器也可以根据需要修改自身的容量和大小。
deque
容器和 vecotr
容器不同处:
deque
还擅长在序列头部添加或删除元素,所耗费的时间复杂度也为常数阶O(1)
。deque
容器中存储元素并不能保证所有元素都存储到连续的内存空间中。
当需要向序列两端频繁的添加或删除元素时,应首选
deque
容器。
2.3.2. 函数
https://zh.cppreference.com/w/cpp/container/deque
2.3.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <deque>
#include <iostream>
using namespace std;
int main() {
deque<int> d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
cout << "原始双端队列:" << endl;
for (int i = 0; i < d.size(); i++) {
cout << d.at(i) << "\t";
}
cout << endl;
d.push_front(5);
d.push_front(3);
d.push_front(1);
cout << "after push_front(5.4.1):" << endl;
for (int i = 0; i < d.size(); i++) {
cout << d.at(i) << "\t";
}
cout << endl;
d.pop_front();
d.pop_front();
cout << "after pop_front() two times:" << endl;
for (int i = 0; i < d.size(); i++) {
cout << d.at(i) << "\t";
}
cout << endl;
return 0;
}
2.4. 对比
vector
:vector
和内置数组类似,拥有一段连续的内存空间,能非常好的支持随即存取,即[]
操作符,但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝。当插入较多的元素后,预留内存空间可能不够,需要重新申请一块足够大的内存并把原来的数据拷贝到新的内存空间。这些影响了vector
的效率,但是实际上用的最多的还是vector
容器,建议大多数时候使用vector
效率一般是不错的。list
:list
就是数据结构中的双向链表(根据sgi stl
源代码),因此它的内存空间是不连续的,通过指针来进行数据的访问,这个特点使得它的随即存取变的非常没有效率,因此它没有提供[]
操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。deque
:deque
是一个double-ended queue
,它具有以下两个特点:它支持[]
操作符,也就是支持随即存取,并且和vector
的效率相差无几,它支持在两端的操作:push_back
,push_front
,pop_back
,pop_front
,并且在两端操作上与list
的效率也差不多。
3. 适配器容器
3.1. stack(堆栈)
3.1.1. 介绍
需要包含头文件 <stack>
,Stack
是一个容器类的改编,实现了一个先进后出(FILO),也称作后进先出(LIFO)的数据结构。
3.1.2. 函数
https://zh.cppreference.com/w/cpp/container/stack
3.1.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <stack>
using namespace std;
void newstack(stack<int> ss) {
stack<int> sg = ss;
while (!sg.empty()) {
cout << sg.top() << " ";
sg.pop();
}
cout << endl;
}
int main() {
stack<int> newst;
newst.push(55);
newst.push(44);
newst.push(33);
newst.push(22);
newst.push(11);
cout << "最新的堆栈是 : ";
newstack(newst);
cout << "\nnewst.size() : " << newst.size();
cout << "\nnewst.top() : " << newst.top();
cout << "\nnewst.pop() : ";
newst.pop();
newstack(newst);
return 0;
}
3.2. queue(队列)
3.2.1. 介绍
需要包含头文件 <queue>
,queue
实现了一个先进先出(FIFO)的容器。
3.2.2. 函数
https://zh.cppreference.com/w/cpp/container/queue
3.2.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> que_int;
// 在队列末尾依次插入11,12,13
que_int.push(11);
que_int.push(12);
que_int.push(13);
// 获取队列中的最后一个元素
int nValue1 = que_int.back();
cout << "The last value of queue is: " << nValue1 << endl;
// 获取队列中的第一个元素
int nValue2 = que_int.front();
cout << "The first value of queue is: " << nValue2 << endl;
// 弹出队列中的第一个元素,之后再获取队列中的第一个元素
que_int.pop();
nValue2 = que_int.front();
cout << "After pop, the first value of queue is: " << nValue2 << endl;
// 返回队列中的元素个数
int nSize = que_int.size();
cout << "The size of queue is: " << nSize << endl;
// 判断队列是否为空
bool bFlag = que_int.empty();
if (bFlag) {
cout << "queue is empty." << endl;
} else {
cout << "queue is not empty." << endl;
}
// 清空队列
que_int = queue<int>();
// 判断队列是否为空
bFlag = que_int.empty();
if (bFlag) {
cout << "After clear, queue is empty." << endl;
} else {
cout << "After clear, queue is not empty." << endl;
}
return 0;
}
3.3. priority_queue(优先队列)
3.3.1. 介绍
需要包含头文件 <queue>
,保证每次的队首元素都是优先级最大的。可以用来解决一些贪心问题,也可以对 Dijkstra 算法进行优化(优先队列的本质是堆)。
3.3.2. 函数
与队列不同,优先队列只能通过 top()
函数来访问队首元素。
https://zh.cppreference.com/w/cpp/container/priority_queue
3.3.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <queue>
using namespace std;
int main() {
priority_queue<int> q;
//入队四个元素:3,4,1,5。默认情况下数字越大,优先级越大
q.push(5);
q.push(4);
q.push(1);
q.push(3);
//出队队首元素:5
q.pop();
//访问队首元素
printf("%d\n", q.top());
//判断队列是否为空
if (q.empty()) {
printf("Empty\n");
} else {
printf("Not Empty\n");
}
//获取队列中剩余元素的个数
printf("%d", q.size());
}
优先级使用:若想实现价格低的水果优先级高,只需将
return f1.price < f2.price;
改为return f1.price > f2.price;
即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <queue>
using namespace std;
struct fruit {
string name;
int price;
} f1, f2, f3;
struct cmp {
bool operator()(fruit f1, fruit f2) {
return f1.price < f2.price;
}
};
int main() {
priority_queue<fruit, vector<fruit>, cmp> q;
f1.name = "桃子";
f1.price = 3;
f2.name = "梨子";
f2.price = 4;
f3.name = "苹果";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
4. 关联式容器
4.1. set/multiset(集合)
set
可实现自动递增排序并去除重复元素的功能。
4.1.1. 介绍
set
是STL
中一个很有用的容器,用来存储同一种数据类型的数据结构(可以称之为K模型),基本功能与数组相似。set
与数组不同的是,在set
中每个元素的值都是唯一的。set
插入数据时,能够根据元素的值自动进行排序。set
中数元素的值并不能直接被改变。
4.1.2. set 底层
set
的底层是红黑树,是红黑树里面K模型;
K模型:表示只能存放同一种数据类型
KV模型:表示能存放两种数据类型
map
的底层也是红黑树,而它是KV模型。set
不允许插入重复数据,而multiset
允许插入相同的数据。
multiset
功能与set
类似,接口也基本一样,最主要的区别是:set
不允许数据冗余,而multiset
允许数据冗余
4.1.3. 函数
https://zh.cppreference.com/w/cpp/container/set
https://zh.cppreference.com/w/cpp/container/multiset
4.1.4. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <set>
using namespace std;
void display(set<int> st) {
if (st.empty()) {
cout << "set is empty" << endl;
return;
}
for (auto i : st) {
cout << i << " ";
}
cout << endl;
}
int main() {
set<int> st;
// 添加
st.insert(1);
st.insert(3);
st.insert(4);
st.insert(5);
cout << "初始集合为:";
display(st);
// 查找,查找不到返回 集合大小
set<int>::iterator it = st.find(2); // 在set中查找2,返回其迭代器
cout << *it << endl;
// 删除一个元素
st.erase(4);
cout << "删除元素集合为:";
display(st);
// 求集合大小
cout << st.size() << endl;
// 清空集合
st.clear();
cout << "清空集合为:";
display(st);
return 0;
}
4.2. map/multimap(映射)
4.2.1. 介绍
map
是 STL
的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在 map
中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。
map
内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在 map
内部所有的数据都是有序的。
4.2.2. 函数
https://zh.cppreference.com/w/cpp/container/map
https://zh.cppreference.com/w/cpp/container/multimap
4.2.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <map>
#include <string.h>
using namespace std;
void display(map<int, string> Map) {
if (Map.empty()) {
cout << "map is empty" << endl;
return;
}
for (auto i : Map) {
cout << i.first << ": " << i.second << endl;
}
cout << endl;
}
int main() {
map<int, string> Employees;
// 使用数组索引符号进行赋值
Employees[101] = "Nikita";
Employees[105] = "John";
Employees[103] = "Dolly";
Employees[102] = "Aman";
Employees[104] = "Deep";
// 插入
Employees.insert(make_pair(99, "Marry"));
// begin 遍历
cout << "自然顺序:" << endl;
for (map<int, string>::iterator ii = Employees.begin(); ii != Employees.end(); ++ii) {
cout << (*ii).first << ": " << (*ii).second << endl;
}
cout << endl;
// rbegin 遍历
cout << "相反顺序:" << endl;
for (map<int, string>::reverse_iterator ii = Employees.rbegin(); ii != Employees.rend(); ++ii) {
cout << (*ii).first << ": " << (*ii).second << endl;
}
cout << endl;
// 查找
cout << Employees.count(99) << endl;
cout << Employees.at(99) << endl;
// 删除
cout << Employees.erase(99) << endl;
display(Employees);
// 清空
Employees.clear();
display(Employees);
return 0;
}
4.3. pair(键值对)
当想要将两个元素绑在一起作为一个合成元素、又不想定义结构体时,可以用 pair
作为结构体的替代品,可以节省编码时间。
4.3.1. 介绍
pair
类模板定义在<utility>
或者 <map>
头文件中,所以在使用该类模板之前,需引入此头文件。另外值得一提的是,在 C++11
标准之前 pair
类模板中提供了以下 3 种构造函数:
1
2
3
4
5
6
#1) 默认构造函数,即创建空的 pair 对象
pair();
#2) 直接使用 2 个元素初始化成 pair 对象
pair (const first_type& a, const second_type& b);
#3) 拷贝(复制)构造函数,即借助另一个 pair 对象,创建新的 pair 对象
template<class U, class V> pair (const pair<U,V>& pr);
在 C++11
标准中,在引入右值引用的基础上,pair
类模板中又增添了如下 2 个构造函数:
1
2
3
4
#4) 移动构造函数
template<class U, class V> pair (pair<U,V>&& pr);
#5) 使用右值引用参数,创建 pair 对象
template<class U, class V> pair (U&& a, V&& b);
4.3.2. 函数
https://zh.cppreference.com/w/cpp/utility/pair
4.3.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <map>
using namespace std;
int main() {
pair<string, int> p1;
pair<string, int> p2;
pair<string, int> p3;
// 创建方式第一种
p1.first = "young";
p1.second = 3;
// 第二种
p2 = make_pair("simple", 0);
// 第三种
p3 = pair<string, int>("naive", 1);
cout << p1.first << " " << p1.second << endl;
cout << p2.first << " " << p2.second << endl;
cout << p3.first << " " << p3.second << endl;
// 比较
pair<int, int> p11(5, 10);
pair<int, int> p22(5, 15);
pair<int, int> p33(10, 5);
if (p11 < p22) {
cout << "p11 < p22" << endl;
}
if (p11 < p33) {
cout << "p11 < p33" << endl;
}
return 0;
}
4.4. tuple(元组)
4.4.1. 介绍
定义于头文件 <tuple>
中。它是 std::pair
的推广,std::tuple
可以看作是多元数据组合。
4.4.2. 函数
https://zh.cppreference.com/w/cpp/utility/tuple
4.4.3. 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <tuple>
using namespace std;
// 打印任何大小 tuple 的帮助函数
template <class Tuple, std::size_t N>
struct TuplePrinter
{
static void print(const Tuple& t)
{
TuplePrinter<Tuple, N - 1>::print(t);
// 获取元素
std::cout << ", " << std::get<N - 1>(t);
}
};
template <class Tuple>
struct TuplePrinter<Tuple, 1>
{
static void print(const Tuple& t)
{
std::cout << std::get<0>(t);
}
};
template <class... Args>
void print(const std::tuple<Args...>& t)
{
std::cout << "(";
TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
std::cout << ")\n";
}
// 结束帮助函数
int main()
{
// 创建
tuple<int, char, string> t1 = make_tuple(1, 'a', "hello");
std::tuple<int, char, string> t2(2, 'b', "world");
// 解包
int a;
string b;
tie(a, ignore, b) = t1;
cout << a << " " << b << endl;
// 交换
swap(t1, t2);
print(t1);
print(t2);
// 连接
auto t3 = tuple_cat(t1, t2);
print(t3);
return 0;
}
5. 无序关联式容器
这类容器对存储数据不会进行排序。
5.1. unordered_set
总的来说,unordered_set
容器具有以下几个特性:
- 不再以键值对的形式存储数据,而是直接存储数据的值;
- 容器内部存储的各个元素的值都互不相等,且不能被修改。
- 不会对内部存储的数据进行排序
5.2. unordered_map
unordered_map
容器和 map 容器一样,以键值对的形式存储数据,存储的各个键值对的键互不相同且不允许被修改。但由于 unordered_map
容器底层采用的是哈希表存储结构,该结构本身不具有对数据的排序功能,所以此容器内部不会自行对存储的键值对进行排序。