C++ STL 标准模板库
STL是C++的标准模板库,提供了非常多通用的算法和数据结构等。它分为多个组件,课程上将会介绍容器(containers,类模板、通用数据结构)、算法(algorithms)和迭代器(iterators,生成指针)。
Containers 容器
Sequential 序列容器
用于存储元素的序列。
向量(动态数组)。动态分配存储空间,支持自增长,因此初始化时无需给定长度,支持随机访问。末尾插入删除复杂度为\(O(1)\),中间为\(O(N)\)
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 创建vector
vector<int> vec_1; // 创建一个空向量
vector<int> vec_2(5); // 包含5个数,均初始化为0
vector<int> vec_3(5, 8); // 包含5个数,均初始化为10
vector<int> vec_4 = {1, 2, 3, 4};
// 插入
vec_1.push_back(8); // 末尾插入8
vec_1.insert(vec_1.begin(), 10); // 在vec_1[0]处插入10
vec_2.insert(vec_2.begin() + 4, 5, 10); // 在vec_2[4]处插入5个10
// 删除
vec_1.pop_back(); // 删除末尾元素
vec_2.erase(vec_2.begin() + 2); // 删除vec_2[2]
vec_3.erase(vec_3.begin() + 2, vec_3.begin() + 4); // 删除vec_3[2]到vec_3[4]之间的所有元素
vec_4.clear(); // 清空
// 大小
cout << vec_4.empty() << endl;
cout << vec_3.size() << endl; // 虽然.size() == 0也可以用来判断是否为空,但它需要线性时间,而empty只需要判断是否为空,因此是常数复杂度的
vec_2.reserve (50); // 预留空间,避免频繁分配内存
cout << vec_2.capacity() << endl; // 实际占用的内存容量
// 访问
cout << vec_2[0] << endl;
cout << vec_2.at(0) << endl;
cout << vec_2.front() << endl;
cout << vec_2.back() << endl;
cout << *(vec_2.data() + 3) << endl; // .data()返回指向第一个元素的指针,+3表示vec_2[3]
// 利用迭代器遍历vector的几种实现
for (vector<int>::iterator it = vec_1.begin(); it < vec_1.end(); ++it)
cout << *it << " ";
cout << endl;
for (auto it = vec_2.begin(); it < vec_2.end(); ++it)
cout << *it << " ";
cout << endl;
for (auto it = begin(vec_3); it < end(vec_3); ++it)
cout << *it << " ";
cout << endl;
for (int i: vec_4)
cout << i << " ";
cout << endl;
// 除了begin()和end()之外,还有cbegin()和cend()
// 区别在于cbegin()和cend()返回的是const_iterator,不能修改元素的值
return 0;
}
双向队列。分块存储,并非完全线性,因此虽然支持随机访问但略慢于vector。头尾插入删除复杂度为\(O(1)\),中间为\(O(N)\)
单向链表
Associative 关联容器
用于存储键值对,每个元素都有一个key和一个value,通过key来组织元素
集合。不允许重复元素
映射。每个键映射到一个值
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> price;
price["apple"] = 10;
price["banana"] = 20;
price["orange"] = 30;
string item;
int total = 0;
while (cin >> item && item != "exit")
if (price.contains(item)) // 如果item在price中
total += price[item]; // 如果item不在price中,会自动创建一个以item为键,值为0的元素
cout << total << endl;
for (const auto &p: price) {
cout << "{" << p.first << "," << p.second << "}" << " ";
}
}
利用map访问不存在的键时自动创建的特性,可以给出如下代码:
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> word_map;
for (const string &word: {"abandon", "ability", "about", "absent", "absorb", "abstract", "absurd"})
++word_map[word]; // 利用不存在就自动创建的特性
for (const auto &[word, count]: word_map) // 可以用[]将键和值写开
cout << word << " " << count << endl;
}
多重集合。允许多个元素具有相同的键
多重映射。存储键值对,键是唯一的,但值可以重复,允许一个键映射到多个值
Unordered Associative 无序容器
用哈希表来实现快速查找、插入和删除。对应关联容器,有unordered_set、unordered_map、unordered_multiset和unordered_multimap
Adaptors 适配容器
适配器可以理解为一个「转接口」,将用户的需求转接到别的基础容器上。比如说,我们可以在vector的基础上添加一些功能(入栈、出栈)来实现栈,或者说,我将用户所需要的栈的功能通过这个适配容器转接到vector上了
栈
#include <iostream>
#include <stack>
#include <string>
using namespace std;
bool isBalanced(const string& s) { // 函数中没有对s进行任何操作,因此声明为常量引用
stack<char> st;
for (char c: s)
if (c == '(' || c == '{' || c == '[')
st.push(c);
else if (c == ')' || c == '}' || c == ']') {
if (st.empty())
return false;
if (c == ')' && st.top() != '(' || c == '}' && st.top() != '{' || c == ']' && st.top() != '[')
return false;
st.pop();
}
return st.empty();
}
int main() {
string test_1 = "a(b{c[d]e}f)g";
string test_2 = "a(b{c[d}e]f)g";
cout << "Test 1: " << (isBalanced(test_1) ? "Balanced" : "Not Balanced") << endl;
cout << "Test 2: " << (isBalanced(test_2) ? "Balanced" : "Not Balanced") << endl;
// 问好冒号表达式最外面的括号不能少
}
队列,用法和栈类似
优先队列(堆),用法和栈类似
Algorithms 算法
STL中有大量的算法,用于对容器中的元素进行操作。算法的调用不需要关注容器的类型,只需要给出操作范围即可(注意区间是前开后闭的)
Iterators 迭代器
迭代器用于遍历容器中的元素,将容器和算法连接起来