学而时习之:C++中的标准模板库8

35 阅读5分钟

C++ STL 中的 Map(键值对)

Map 是关联容器,以 键-值对(key-value) 的形式按 键排序 存储数据。它基于 自平衡二叉搜索树(具体为 红黑树),因此具备以下特性:

  • 查找、插入、删除的时间复杂度均为 O(log n)
  • 自动禁止 重复键
  • 键按 升序 排列。
  • unordered_map 相比,map 的搜索、插入、删除稍慢,但能获得 有序结果,并支持 upper_bound()lower_bound() 等额外操作。
#include <iostream>
#include <map>
using namespace std;

int main() {
    // 创建空 map
    map<int, string> m1;

    // 使用初始化列表创建 map
    map<int, string> m2 = {
        {1, "Geeks"},
        {2, "For"},
        {3, "Geeks"}
    };

    // 遍历并打印
    for (auto& p : m2){
        cout << p.first << " " << p.second << endl;
    }

    return 0;
}
1 Geeks
2 For
3 Geeks

语法

map 容器在头文件 <map> 中被定义为 std::map 类模板。

map<键, 值> m;

其中:

  • 键类型:键(key)的数据类型。
  • 值类型:值(value)的数据类型。
  • m:给 map 起的名字。

基本操作

下文展示 map 容器的基础操作:

1.插入元素

insert() 用于向 map 新增键值对。

  • 只有当 键尚不存在 时才会成功插入;
  • 若键已存在,insert() 不会更新原值,map 保持不变。 插入时间复杂度:O(log n)
#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, string> m = { {2, "For"}, {3, "Geeks"} };

    // 插入一对新键值
    m.insert({1, "Geeks"});

    for (auto x : m){
        cout << x.first << " " << x.second << endl;
    }
    return 0;
}
1 Geeks
2 For
3 Geeks

2.访问元素

可以使用 [] 运算符访问元素,它根据给定的键返回值;

(1)若该键不存在,[]自动插入该键,并将其值设为默认值。
(2)若想仅检查键是否存在而不插入,可使用 find()

按键访问的时间复杂度:O(log n)

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, string> m = {
        {1, "Geeks"},
        {2, "For"},
        {3, "Geeks"}
    };

    // 访问元素
    cout << m[1] << endl;     // 使用 []
    cout << m.at(2);          // 使用 at()

    return 0;
}
Geeks
For

3.更新元素

要更新某个键对应的值,只需使用 map[key] = 新值 即可。
若该键已存在,其值会被更新;若不存在,会新建该键值对。也可使用 at() 进行更新(但键必须已存在,否则会抛出异常)。
更新操作的时间复杂度:O(log n)

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, string> m = {
        {1, "Geeks"},
        {2, "For"},
        {3, "Geeks"}
    };

    // 更新值
    m[0] = "Tweaks";     // 插入新键 0
    m.at(1) = "By";      // 更新键 1 的值

    cout << m[0] << endl;
    cout << m.at(1);
    return 0;
}
Tweaks
By

4.查找元素

find() 函数用于检查某个键是否存在于 map 中。

  • 若找到,返回指向该键值对的迭代器
  • 若未找到,返回 end(),表示“不存在”。
    查找时间复杂度:O(log n)
#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, string> m = {
        {1, "Geeks"},
        {2, "For"},
        {3, "Geeks"}
    };

    // 查找键为 2 的元素
    auto it = m.find(2);

    if (it != m.end())
        cout << it->first << " " << it->second;
    else
        cout << "未找到该键!";

    return 0;
}
2 For

5.遍历

可以使用循环遍历 map 中的所有键值对,访问顺序按键的升序排列。
遍历时间复杂度:O(n)

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, string> m = {
        {1, "Geeks"},
        {2, "For"},
        {3, "Geeks"}
    };

    // 使用迭代器遍历
    for (auto it = m.begin(); it != m.end(); ++it){
        cout << it->first << " " << it->second << endl;
    }

    return 0;
}
1 Geeks
2 For
3 Geeks

6.删除元素

要从 map 中删除某个键及其对应的值,可使用 erase(key)
若该键存在,则删除整对键值,否则不做任何操作。
也可传入迭代器删除指定位置。
删除时间复杂度:O(log n)

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, string> m = {
        {1, "Geeks"},
        {2, "For"},
        {3, "Geeks"}
    };

    // 按键删除
    m.erase(2);

    // 按迭代器删除
    m.erase(m.begin());

    for (auto i : m)
        cout << i.first << " " << i.second << endl;

    return 0;
}
3 Geeks

C++ STL 中的 Set(集合)

Set 是一个容器,用于存储不重复的元素,并按一定顺序排列。 它基于自平衡二叉搜索树(具体为红黑树),因此具备以下特性:

  • 查找、插入、删除的时间复杂度均为 O(log n)
  • 不允许重复元素
  • 默认按升序排列,也可通过自定义比较器指定排序规则。
  • unordered_set 相比,操作稍慢,但能得到有序序列,并支持 upper_bound()lower_bound() 等额外功能。
#include <iostream>
#include <set>
using namespace std;

int main() {
    // 创建空集合
    set<int> s1;

    // 使用初始化列表创建集合(重复值会被自动去重)
    set<int> s2 = {1, 2, 3, 2, 1};

    // 遍历集合
    for (auto& x : s2){
        cout << x << " ";
    }
    cout << endl;

    return 0;
}
1 2 3

语法

set 容器在头文件 <set> 中被定义为 std::set 类模板。

set<元素类型> s;

其中:

  • 元素类型:集合中元素的数据类型。
  • s:给集合起的名字。

基本操作

下面展示 set 容器的常用操作:

1.插入元素

insert() 仅当元素尚不存在时才将其加入集合;若元素已存在,insert() 什么也不做(集合不允许重复)。

#include <iostream>
#include <set>
using namespace std;

int main() {
    // 用初始值构造集合
    set<int> s = {2, 3};

    // 插入新元素
    s.insert(1);

    // 遍历集合
    for (auto x : s)
        cout << x << endl;

    return 0;
}
1
2
3

2.查找元素

  • find() 用于检查某个元素是否存在:
    • 若找到,返回指向该元素的迭代器
    • 若未找到,返回 end()
  • count() 也可用来判断存在性:存在返回 1,不存在返回 0
#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s = {1, 2, 3};

    // 使用 find() 查找
    auto it = s.find(1);
    if (it != s.end())
        cout << "找到元素: " << *it << endl;

    // 使用 count() 判断存在
    if (s.count(2))
        cout << "2 存在于集合中" << endl;

    // 遍历输出所有元素
    cout << "所有元素: ";
    for (auto x : s)
        cout << x << " ";
    cout << endl;

    return 0;
}
找到元素: 1
2 存在于集合中
所有元素: 1 2 3

3.遍历

可以使用循环(如范围 for 或迭代器)遍历集合中的所有元素。 遍历顺序即为元素在集合中的有序顺序(默认升序,或按自定义比较器)。

#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s = {1, 2, 3};

    // 使用迭代器遍历
    for (auto it = s.begin(); it != s.end(); ++it)
        cout << *it << endl;

    return 0;
}
1
2
3

4.删除元素

使用 erase() 可从集合中删除指定元素:

  • 若元素存在,则删除;
  • 若不存在,什么也不做。
#include <iostream>
#include <set>
using namespace std;

int main() {
    set<int> s = {1, 2, 3, 4};

    // 按值删除
    s.erase(2);

    // 按迭代器删除
    s.erase(s.begin());

    // 遍历集合
    for (auto i : s)
        cout << i << " ";
    cout << endl;

    return 0;
}
3 4