0
#LS0006. 【课件】STL库的应用

【课件】STL库的应用

當前沒有測試資料。

1、什么是 STL 库

  • STL 即标准模板库(Standard Template Library),是 C++ 标准库的一部分,里面包含了一些模板化的通用的数据结构和算法,可以极大简化代码,对暴力题和骗分题极其友好
  • 所以,大家务必从头到尾仔细阅读本课件,你会发现原来写代码可以这么简单

2、常用数学函数

  • max, min, abs, floor, ceil, round, sqrt 具体见如下代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    int a = 1, b = 3;
    double c = 2.0;

    // max(a, b), 用于返回 a, b 中较大的值
    // 注意: a, b 一定要是同类型的值
    // 输出: max(a, b)返回 a, b 中较大的数是: 3
    cout << "max(a, b)返回 a, b 中较大的数是: " << max(a, b) << '\n';
    // 错误: a 是 int, c 是 double, 会报编译错误
    // cout << max(a, c) << '\n';
    cout << '\n';

    // min(a, b), 用于返回 a, b 中较小的值
    // 注意: a, b 一定要是同类型的值
    // 输出: min(a, b)返回 a, b 中较小的数是: 1
    cout << "min(a, b)返回 a, b 中较小的数是: " << min(a, b) << '\n';
    cout << '\n';

    // abs(a) 返回 a 的绝对值
    // 输出: abs(1.2) 返回 1.2 的绝对值是: 1.2
    cout << "abs(1.2) 返回 1.2 的绝对值是: " << abs(1.2) << '\n';
    // 输出: abs(-1.2) 返回 -1.2 的绝对值是: 1.2
    cout << "abs(-1.2) 返回 -1.2 的绝对值是: " << abs(-1.2) << '\n';
    cout << '\n';

    // floor(x) 返回不超过 x 的最大 int 值
    // 输出: floor(5) 返回不超过 5 的最大整数是: 5
    cout << "floor(5) 返回不超过 5 的最大整数是: " << floor(5) << '\n';
    // 输出: floor(5.9) 返回不超过 5.9 的最大整数是: 5
    cout << "floor(5.9) 返回不超过 5.9 的最大整数是: " << floor(5.9) << '\n';
    // 输出: floor(-5.9) 返回不超过 -5.9 的最大整数是: -6
    cout << "floor(-5.9) 返回不超过 -5.9 的最大整数是: " << floor(-5.9) << '\n';
    cout << '\n';

    // ceil(x) 返回不小于 x 的最大 int 值
    // 输出: ceil(5) 返回不小于 5 的最大整数是: 5
    cout << "ceil(5) 返回不小于 5 的最大整数是: " << ceil(5) << '\n';
    // 输出: ceil(5.9) 返回不小于 5.9 的最大整数是: 6
    cout << "ceil(5.9) 返回不小于 5.9 的最大整数是: " << ceil(5.9) << '\n';
    // 输出: ceil(-5.9) 返回不小于 -5.9 的最大整数是: -5
    cout << "ceil(-5.9) 返回不小于 -5.9 的最大整数是: " << ceil(-5.9) << '\n';    
    cout << '\n';

    // round(x) 用于返回 x 四舍五入后的结果
    // 输出: round(5.4)=5
    cout << "round(5.4)=" << round(5.4) << '\n';
    // 输出: round(5.5)=6
    cout << "round(5.5)=" << round(5.5) << '\n';
    // 输出: round(-5.4)=-5
    cout << "round(-5.4)=" << round(-5.4) << '\n';
    // 输出: round(-5.5)=-6
    cout << "round(-5.5)=" << round(-5.5) << '\n'; 
    cout << '\n';

    // sqrt(x) 返回 x 开方的结果
    // 输出: sqrt(9)=3
    cout << "sqrt(9)=" << sqrt(9) << '\n';
    // 输出: sqrt(10)=3.16228
    cout << "sqrt(10)=" << sqrt(10) << '\n';   
    return 0;
}

3、迭代器

  • 我们在 【课件】指针与函数 中学习过数组和指针的关系(回忆下,数组名就是指向数组第一个元素的指针)
  • 对于向量容器 vector 来说, 迭代器就是 vector 的指针,可以用来标记 vector 中的某个位置
#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> a;
    for (int i = 0; i < 5; i++) a.push_back(i * 2);
    
    // 输出: 0 2 4 6 8
    for (int i = 0; i < a.size(); i++) cout << a[i] << ' ';
    cout << '\n';
    
    // a.beign() 返回指向 a[0] 的指针
    // 可以通过 *a.beign() 来获取 a[0] 的值
    cout << *a.begin() << '\n';           // 输出: 0

    // 迭代器可以做加法, 返回 a[1] 的值
    cout << *(a.begin() + 1) << '\n';     // 输出: 2

    // 返回 a[2] 的值
    cout << *(a.begin() + 2) << '\n';     // 输出: 4

    // a.end() 指向末尾元素的后一个(不存在的)元素
    // 可以通过 a.end() - a.begin() 计算 a 中元素的个数
    // 也可以用 a.size()
    cout << a.end() - a.begin() << '\n';  // 输出: 5
    
    // 可以通过迭代器来遍历 a
    // auto 可以代指任意类型
    // 输出: 0 2 4 6 8
    for (auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    cout << '\n';

    // 下面的方法更简单
    // 输出: 0 2 4 6 8
    for (int x: a) cout << x << ' ';
    cout << '\n';

    // 也可以把 int x 换成 auto x
    // 输出: 0 2 4 6 8
    for (auto x: a) cout << x << ' ';
    cout << '\n';
    return 0;
}
  • 可以通过 max_element(a.begin(), a.end()),返回 a 中的最大值的迭代器
  • 可以通过 reverse(a.begin(), a.end()) 来返回 a 中的值
  • 假设 a 已经排好序,可以通过 unique(a.begin(), a.end()) 将 a 中相邻的重复元素去掉,返回新的 end 迭代器
  • 还可以通过 a.erase(迭代器1, 迭代器2), 输出 2 个迭代器之间的元素
#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<int> a = {2, 4, 4, 5, 2};

    // 输出: 2 4 4 5 2
    for (auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    cout << '\n';
    
    // 输出: 5, 表示 a 中最大的元素是 5
    cout << *max_element(a.begin(), a.end()) << '\n';
    // 输出: 3, 表示 a 中最大的素数是 a[3]
    cout << max_element(a.begin(), a.end()) - a.begin() << '\n';
    
    // 翻转 a
    reverse(a.begin(), a.end());
    // 输出: 2 5 4 4 2
    for (auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    cout << '\n';

    // 将 a 从小到大 排序
    sort(a.begin(), a.end());
    // 输出: 2 2 4 4 5
    for (auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    cout << '\n';

    // 通过 unique 去重, 返回新的 end
    auto new_end = unique(a.begin(), a.end());
    // 输出: 2 4 5
    for (auto i = a.begin(); i != new_end; i++) cout << *i << ' ';
    cout << '\n';

    // 还可以通过 erase 将 a 中去重后多余的部分删掉
    // 这个时候 a.end() 就等于 new_end 了
    a.erase(new_end, a.end());
    // 输出: 2 4 5
    for (auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    cout << '\n';
    return 0;
}

4、pair 类型

  • pair 类型可以将 2 个值绑定到一个变量中(这个 2 个值可以是同一类型,也可以是不同类型)
#include <bits/stdc++.h>
using namespace std;

int main() {
    // pair<int, int> 表示将 2 个 int 类型的值绑定成新的类型
    pair<int, int> a;
    // 可以通过 a.first 获取第 1 个数, a.second 获取第二个数
    a.first = 1, a.second = 2;

    // 可以将不同类型的 2 个值绑定
    // 比如第 1 个是 int 类型, 第 2 个是 double 类型
    // 可以通过 {1, 1.5} 的形式生成 pair<int, double> 类型
    pair<int, double> b = {1, 1.5};
    // 输出: 1 1.5
    cout << b.first << ' ' << b.second << '\n';

    // 绑定 string 和 int
    // 输出: liangsheng 32
    pair<string, int> c = {"liangsheng", 32};
    cout << c.first << ' ' << c.second << '\n';

    // 还可以绑定 vector
    vector<int> arr = {1, 2, 3, 4};
    pair<int, vector<int>> d = {1, arr};
    // 输出: 1
    cout << d.first << '\n';
    // 输出: 1 2 3 4
    for (auto x : d.second) cout << x << ' ';
    cout << '\n';

    // pair 也可以嵌套绑定
    pair<int, pair<int, int>> e = {1, {2, 3}};
    // 输出: 1
    cout << e.first << '\n';
    // 输出: 2 3
    cout << e.second.first << ' ' << e.second.second << '\n';
    return 0;
}

5、序列容器

5-1、vector

  • vector 大家已经比较熟悉
  • 变长数组 vector 是标准模板库中的一种线性容器
    • 数据在内存中连续存放,可以按下标任意访问
    • 可以很快地在容器尾添加和删除元素
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 申明数组 a, 包含 10 个 int 类型变量, 初始值都是 1
    vector<int> a(10, 1);

    // 通过 b.push_back(1) 在数组末尾添加元素
    vector<int> b;
    b.push_back(1);
    b.push_back(2);

    // 通过 b.size() 获取数组的长度
    // 输出: 1 2
    for (int i = 0; i < b.size(); i++) cout << b[i] << ' ';
    cout << '\n';

    // 申明 2 维数组 int b[10][5],并且初始化全为 0
    vector<vector<int>> b(10, vector<int>(5, 0));

    // 申明 2 维数组 c(并未指定大小)
    vector<vector<int>> c;

    // 通过 assign 函数将 c 重置为 int c[3][4],并初始化为 0
    c.assign(3, vector<int>(4, 0));
    return 0;
}
  • 还有很多关于 vector 中迭代器的用法,可参考本课件的迭代器部分

5-2、deque

  • 除了在容器末尾添加元素,有时我们还需要在容器开头添加元素
  • 可以使用标准模板库中的 deque 容器
    • 不保证数据在内存中连续存放,但可以按下标任意访问
    • 可以很快地在容器的头尾添加和删除元素
    • 要在容器头添加元素,使用 push_front
    • 要在容器头删除元素,使用 pop_front
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;

int main() {
    deque<int> a;
    
    // 通过 push_back 在 a 末尾添加元素
    a.push_back(1);  // a = [1]
    a.push_back(2);  // a = [1, 2]
    a.push_back(3);  // a = [1, 2, 3]

    // 通过 push_front 在 a 开头添加元素
    a.push_front(4);  // a = [4, 1, 2, 3]
    a.push_front(5);  // a = [5, 4, 1, 2, 3];

    // 通过迭代器遍历 a 中的元素
    for (auto i = a.begin(); i != a.end(); i++) cout << *i << ' ';
    cout << '\n';

    // 通过下标访问 a 中的元素
    cout << a[0] << '\n';  // a[0] = 5;
    cout << a[1] << '\n';  // a[1] = 4;
    cout << a[2] << '\n';  // a[2] = 1;

    // 删除 a 中最前面的元素
    a.pop_front();  // a = [4, 1, 2, 3]
    for (int x : a) cout << x << ' ';
    cout << '\n';

    // 删除 a 中最后面的元素并
    a.pop_back();  // a = [4, 1, 2]
    for (int x : a) cout << x << ' ';
    cout << '\n';

    return 0;
}

5-3、queue

  • 队列(queue)是 deque 的特殊情况
  • 队列(queue) 要求所有元素先进先出
  • 队列(queue) 总是在末尾添加元素,在开头删除元素
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 申明队列时,需要指明类型
    queue<string> qs;
    queue<int> q;

    // 通过 push 或者 emplace, 往队列里添加元素
    // push 和 emplace 几乎是一样的
    q.push(1);     // q = [1]
    q.push(2);     // q = [1, 2]
    q.emplace(3);  // q = [1, 2, 3]

    // 通过 front() 取队列开头的元素
    int x = q.front();
    cout << "x= " << x << '\n';  // x = 1
    // 通过 pop() 将队列开头的元素弹出, q 变成 [2, 3]
    q.pop();

    int y = q.front();
    cout << "y= " << y << '\n';  // y = 2
    q.pop();                     // q = [3]
    return 0;
}
  • 队列(queue)也可以用 vector 来实现
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 假设队列最长是 100, l 和 r 分别指向队列的头和尾的后一个位置
    int n = 100, l = 0, r = 0;
    vector<int> q(n);

    // 往队列里添加元素
    q[r++] = 1;  // q = [1]
    q[r++] = 2;  // q = [1, 2]
    q[r++] = 3;  // q = [1, 2, 3]

    // 取队列开头元素
    int x = q[l];
    cout << "x= " << x << '\n';  // x = 1
    // 通过 l++ 将队列开头的元素弹出, q 变成 [2, 3]
    l++;

    int y = q[l];
    cout << "y= " << y << '\n';  // y = 2
    l++;                         // q = [3]
    return 0;
}

5-4、stack

  • 栈(stack)是 deque 的特殊情况
  • 栈(stack)要求所有元素后进先出.
  • 栈(stack) 总是在末尾添加元素,在末尾删除元素
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 申明栈时,需要指明类型
    stack<int> s;

    // 通过 push 或者 emplace, 往栈里添加元素
    // push 和 emplace 几乎是一样的
    s.push(1);     // s = [1]
    s.push(2);     // s = [1, 2]
    s.emplace(3);  // s = [1, 2, 3]

    // 通过 front() 取栈顶的元素
    int x = s.top();
    cout << "x= " << x << '\n';  // x = 3
    // 通过 pop() 将栈顶的元素弹出, s 变成 [2, 3]
    s.pop();

    int y = s.top();
    cout << "y= " << y << '\n';  // y = 2
    s.pop();                     // s = [3]
    return 0;
}
  • 栈(stack)也可以用 vector 来实现
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 假设栈最长是 100, e 表示栈里元素的个数, 初始是 0
    int n = 100, e = 0;
    vector<int> s(n);

    // 往栈里添加元素
    s[e++] = 1;  // s = [1]
    s[e++] = 2;  // s = [1, 2]
    s[e++] = 3;  // s = [1, 2, 3]

    // 取栈顶头元素
    int x = s[e - 1];
    cout << "x= " << x << '\n';  // x = 3
    // 通过 e-- 将栈顶的元素弹出, s 变成 [1, 2]
    e--;

    int y = s[e - 1];
    cout << "y= " << y << '\n';  // y = 2
    e--;                         // s = [3]
    return 0;
}

5-5、priority_queue

  • 每次删除优先级最大的元素,不管这个元素是什么时候添加的
  • 这个数据结构称为优先队列(prioriyt_queue)
  • 下面的代码使用 priority_queue,将元素从大到小输出,也就是堆排序
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 优先队列申明时需要指明类型, 默认优先取出最大值
    priority_queue<string> qs;
    priority_queue<int> q;

    q.push(1);
    q.push(5);
    q.push(4);
    q.push(2);
    q.push(3);

    // 可以通过 empty() 判断是否为空, queue 和 stack 也有 empty() 方法
    // 输出: 5 4 3 2 1
    while (!q.empty()) {
        int x = q.top();    // 通过 top() 每次取出最大元素
        cout << x << ' ';
        q.pop();            // 通过 pop() 将当前最大元素删除
    }
    cout << '\n';
    return 0;
}
  • 如果每次需要删除的是最小的数,可以在 push 的时候将数取反
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 优先队列申明时需要指明类型, 默认优先取出最大值
    priority_queue<int> q;

    // 如果每次需要删除的是最小的数,可以在 push 的时候将数取反
    q.push(-1);
    q.push(-5);
    q.push(-4);
    q.push(-2);
    q.push(-3);

    // 输出: 1 2 3 4 5
    while (!q.empty()) {
        int x = q.top();    // 通过 top() 每次取出最大元素
        cout << -x << ' ';  // 输出的时候取反
        q.pop();            // 通过 pop() 将当前最大元素删除
    }
    cout << '\n';
    return 0;
}
  • 或者再申明的时候告诉 priority_queue 每次删除最小的
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 申明有限队列时, 指定每次删除最小的
    // 第 1 个参数 int 是指优先队列里的元素类型
    // 第 2 个参数 vector<int> 是有限队列的实现方式
    // 第 3 个参数 greater<int> 告诉优先队列 top() 取最小的数
    priority_queue<int, vector<int>, greater<int>> q;

    q.push(1);
    q.push(5);
    q.push(4);
    q.push(2);
    q.push(3);

    // 输出: 1 2 3 4 5
    while (!q.empty()) {
        int x = q.top();    // 通过 top() 每次取出最大元素
        cout << x << ' ';  // 输出的时候取反
        q.pop();            // 通过 pop() 将当前最大元素删除
    }
    cout << '\n';
    return 0;
}

6、关联容器

6-1、set

  • set 代表集合容器,用以 有序地存储互异元素的容器
  • 每次添加新元素到集合时,都会判断该元素是否已经在集合里面
    • 如果不在,则将该元素插入
    • 如果存在,则什么也不做
  • set 由红黑树实现(一类平衡二叉树,以后会讲到)
  • insert(插入), erase(删除), find(查找), count(查找)的时间复杂度都是 O(log(n))O(log(n))nn 是 set 中元素的个数
#include <bits/stdc++.h>
using namespace std;

int main() {
    set<int> s;

    // 插入集合 s 中的元素, 默认从小到大排列
    // 所以 set 也可以用来排序
    s.insert(3);  // s = {3}
    s.insert(2);  // s = {2, 3}
    s.insert(1);  // s = {1, 2, 3}
    s.insert(1);  // s = {1, 2, 3}, 元素 1 本来就存在

    // 通过 s.beign() 获取 s 中最小的数的迭代器
    // 通过 * 解引用, 可以获取迭代器指向的具体指
    cout << *s.begin() << '\n';   // 输出: 1

    // 通过 s.rbeign() 获取 s 中最小的数的迭代器
    cout << *s.rbegin() << '\n';  // 输出: 3 

    // 输出: 1 2 3
    for (int x : s) cout << x << ' ';
    cout << '\n';

    // 还可以通过迭代器遍历
    // 输出: 1 2 3
    for (auto i = s.begin(); i != s.end(); i++) cout << *i << ' ';
    cout << '\n';

    // 通过 s.count(x) 判断元素 x 是否在集合 s 中
    cout << (s.count(1) ? "s 中存在 1" : "s 中不存在 1") << '\n';
    cout << (s.count(4) ? "s 中存在 4" : "s 中不存在 4") << '\n';

    // 如果 s 中存在 x, 可以通过 s.find(x) 找到 x 对应的迭代器
    if (s.count(2)) {
        auto it = s.find(2);
        // 输出: 1, 也就是集合 s 中 2 的前一个数
        // 这里需要判断 it 是否是 s 的第 1 个指针
        // 如果 it == s.beign(), it 就不能再往前移
        if (it != s.begin()) {
            auto pre = it;
            cout << *(--pre) << '\n';
        }
        
        // 输出: 3, 也就是集合 s 中 2 的后一个数
        auto after = it;
        // 这里需要判断 after == s.end()
        if (++after != s.end()) cout << *after << '\n';
    }

    // 可以通过 s.erase(x), 删除 s 中的元素
    // 如果 s 中存在 x, 则删除 x; 否则, 就什么也不做
    s.erase(1);
    // 输出: 2 3
    for (int x : s) cout << x << ' ';
    cout << '\n';

    // erase() 里面的参数也可以是迭代器
    s.erase(s.find(2));
    // 输出: 3
    for (int x : s) cout << x << ' ';
    cout << '\n';

    // 通过 s.size() 获取 s 中元素的个数
    // 输出: 1
    cout << s.size() << '\n';

    // 通过 s.empty() 判断 s 是否为空集合
    // 输出: s 不为空
    cout << (s.empty() ? "s 为空" : "s 不为空") << '\n';

    // 通过 s.clear(),可以将 s 清空
    s.clear();
    cout << (s.empty() ? "s 为空" : "s 不为空") << '\n';
    return 0;
}
  • set 中的元素默认会去重,如果想插入相同的数,可以利用 pair 类型, 给要插入的数匹配一个序
#include <bits/stdc++.h>
using namespace std;

int main() {
    set<int> s;

    s.insert(1);
    s.insert(2);
    s.insert(2);  // set 会去重, 前面已经插入过 2, 这里不会生效

    // 输出: 1 2
    for (int x : s) cout << x << ' ';
    cout << '\n';

    // 如果想插入相同的数, 可以利用 pair 类型, 给要插入的数匹配一个序号
    // pair 类型只有 pair 中的 2 个数都相同, 才会被判定相同
    // 而 pair 之间比较大小, 是先比较 first, 再比较 second
    set<pair<int, int>> ns;
    ns.insert({1, 1});  // 第 1 次插入 1
    ns.insert({2, 2});  // 第 2 次插入 2
    ns.insert({2, 3});  // 第 3 次插入 2

    // 输出: 1 2 2
    for (auto i : ns) cout << i.first << ' ';
    cout << '\n';
    return 0;
}

6-2、map

  • 之前学过了数组,可以把下标对应到元素
    • a[1] = 2, 相当于把下标 1 对应到 2
    • a[5] = 9, 相当于把下标 5 对应到 9
  • 如果我们的下标不是整数,是字符串怎么办?
    • 比如我想存储每个学生的姓名和成绩
    • 小明 80 分:"xiaoming" -> 80
    • 小红 90 分:"xiaohong" -> 90
  • 可以使用 map,在两种任意类型的数据之间,形成映射
  • 可以把 map 理解为,下标是任意类型,值也是任意类型的数组!!
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 将 string 映射到 int
    // 我们把第 1 个类型 string 称为 key (键) 
    // 把第 2 个类型 int 称为 value (值)
    map<string, int> m;

    // Bob 对应 80 分; Dog 对应 60 分; Alice 对应 90 分
    m["Bob"] = 80;
    m["Dog"] = 60;
    m["Alice"] = 90;
    
    // 可以通过下面的方式遍历 m
    // i 是 pair<string, int> 类型
    // 可以通过 i.first 获取 key, 通过 i.second 获取 value
    // m 中的元素是按 key 值从小到大排序的
    // 输出: Alice 90
    // 输出: Bob 80
    // 输出: Dog 60
    for (auto i: m) {
        cout << i.first << ' ' << i.second << '\n';
    }

    // 会修改 Alice 对应的值
    m["Alice"] = 95;
    cout << "Alice 对应的值是: " << m["Alice"] << '\n';

    // 也可以通过迭代器遍历
    // 这里 i 是 pair<string, int> 类型的迭代器
    // 可以通过 i->first, i->second 获取值
    for (auto i = m.begin(); i != m.end(); i++) {
        cout << (i->first) << ' ' << (i->second) << '\n';
    }

    // 可以通过 m.count("Bob") 查看 m 中是否存在 Bob 对应的值
    if (m.count("Bob")) cout << "Bob 对应的值是: " << m["Bob"] << endl;
    else cout << "不存在 Bod 对应的值" << '\n';
    
    // 可以通过 m.empty() 判断 m 是否为空
    // 可以通过 m.size() 获取 m 中映射的个数
    if (m.empty()) cout << "m 是空" << endl;
    else cout << "m 的大小是: " << m.size() << '\n';

    // 可以通过 m.erase("Dog") 删除 key 是 Dog 的映射
    // 如果不存在 key 是 Dog 的映射, 则什么也不做
    m.erase("Dog");
    for (auto i : m) cout << i.first << ' ' << i.second << '\n';

    // 通过 m.clear(),可以将 m 清空
    m.clear();
    cout << (m.empty() ? "m 为空" : "m 不为空") << endl;

    // key 和 value 可以使复杂类型
    // key 是 int, value 是 vector<int>
    map<int, vector<int>> a;
    a[123] = {1, 2, 3};
    a[456] = {7, 8, 9};
    // 输出: key= 123, value= 1 2 3
    // 输出: key= 456, value= 7 8 9
    for (auto i : a) {
        cout << "key= " << i.first;
        cout << ", value= "; 
        for (int j : i.second) cout << j << ' ';
        cout << '\n';
    }

    // key 是 vector<int>, value 是 string
    map<vector<int>, string> b;
    b[{1, 2, 3, 4}] = "Hello";

    // 在 map 中, 不存在的 key 对应 0(当 value 是 int 时)
    map<int, int> t;
    cout << t[0] << '\n';  // 输出: 0

    // 在 map 中, 不存在的 key 对应空数组(当 value 是 vector<int> 时)
    map<int, vector<int>> tr;
    cout << tr[0].size() << '\n';  // 输出: 0

    // 思考下下面这个复杂的 map, 要如何遍历
    map<vector<int>, pair<int, set<int>>> f;
    for (auto i : f) {
        // i.first 是 vector<int>
        cout << "key: " << '\n';
        for (int j : i.first) cout << ' ';
        cout << '\n';

        // i.second 是 pair<int, set<int>>
        cout << "value: " << '\n';
        // i.second.first 是 int
        cout << i.second.first << '\n';
        // i.second.second 是 set<int>
        for (int j : i.second.second) cout << j << ' ';
        cout << '\n';
    }
    return 0;
}
  • 和 set 一样,map 也是由红黑树实现(一种平衡二叉树,以后会讲)
  • 插入,find(查找),count(查找),erase(删除)的时间复杂度都是 O(log(n))O(log(n))nn 是 map 中元素的个数