首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C++】2.4 map和set的使用

【C++】2.4 map和set的使用

作者头像
用户11952558
发布2026-01-09 14:10:59
发布2026-01-09 14:10:59
1030
举报

1. 序列式容器和关联式容器

  • 序列式容器:逻辑结构为线性序列,交换数据后,性质依旧不变
  • 关联式容器:两个位置联系紧密,交换会破坏存储结构

2. Set的使用

2.1 概况
  • 底层结构:红黑树(平衡二叉搜索树)
  • 声明:数据类型 + 仿函数 + 容器(后两个参数可有默认值)
  • 迭代器:双向迭代器,通过中序遍历得到有序数组
  • 构造方式:与list类似
    • 默认构造
    • 迭代器范围构造
    • 拷贝构造
    • 初始化列表构造
2.2 主要特点
  • 有容量相关接口,但使用不多
  • 支持增(insert)、删(erase)、查(find)操作
  • 不支持修改,因为修改可能破坏红黑树性质
2.3 去重与打印
代码语言:javascript
复制
set<int> se;
se.insert(2);
se.insert(2);
se.insert(5);

for (auto& e : se)
{
    cout << e << " ";
}
cout << endl;

特点

  • Set会自动去重
  • 迭代器中序遍历,打印有序数组
2.4 仿函数的使用
代码语言:javascript
复制
// 使用greater仿函数实现降序
set<int, greater<int>> se;
se.insert(2);
se.insert(2);
se.insert(5);

// 自定义仿函数
template<class T>
struct Greater
{
    bool operator()(const T& a, const T& b) const
    {
        return a > b;
    }
};

set<int, Greater<int>> se;
2.5 初始化列表初始化
代码语言:javascript
复制
set<int> se;
se.insert({ 2,8,3,9,2 });

本质是遍历初始化列表再插入数据,同样会自动去重。

2.6 删除操作

删除最小值

代码语言:javascript
复制
set<int> se;
se.insert({ 2,8,3,9,2 });
se.erase(se.begin());  // 中序遍历,begin迭代器指向最小值

删除指定值

代码语言:javascript
复制
set<int> se;
se.insert({ 2,8,3,9,2 });
int num = se.erase(3);
int num2 = se.erase(10);
cout << num << endl;   // 输出:1
cout << num2 << endl;  // 输出:0
  • 成功删除返回删除的个数(set为1,为了和map保持一致)
  • 失败返回0
2.7 查找操作比较
代码语言:javascript
复制
set<int> se;
se.insert({ 2,8,3,9,2 });

auto it = find(se.begin(), se.end(), 9);  // 库里的find,复杂度O(n)
auto it2 = se.find(9);                    // set的find接口,复杂度O(log n)
2.8 count函数
代码语言:javascript
复制
// 返回值的个数(在set中为0或1,为了和multiset对应)
if (se.count(3))
{
    cout << "有3" << endl;
}

// 对比find方法
auto sit = se.find(3);
if(sit != se.end())
{
    cout << "有3" << endl;
}
2.9 lower_bound和upper_bound
  • lower_bound:找第一个>=指定值的元素
  • upper_bound:找第一个>指定值的元素
代码语言:javascript
复制
auto low_it = se.lower_bound(60);
auto up_it = se.upper_bound(60);
cout << *low_it << " " << *up_it << endl;

3. Multiset

允许值冗余的set

3.1 查找操作
代码语言:javascript
复制
multiset<int> mset = { 2,4,4,3,4,6 };
auto it = mset.find(4);  // 找到中序遍历的第一个4

while (it != mset.end() && *it == 4)
{
    cout << *it;
    ++it;
}
// 这样,就可以通过遍历,把所有元素找到
3.2 删除操作
代码语言:javascript
复制
mset.erase(4);  // 删除所有值为4的元素
// erase也可以传迭代器,并返回新的迭代器

4. Map的使用

4.1 概况

总体框架与set类似,但是支持[]重载修改val。

4.2 Pair结构
代码语言:javascript
复制
pair<int, int> p = { 1,1 };
cout << p.first << ":" << p.second;

// 简易实现
template<class T1, class T2>
struct pair
{
    pair()
        :first(T1())
        , second(T2())
    { }
    
    pair(T1& _first, T2& _second)
        :first(_first)
        ,second(_second)
    { }
    
    T1 first;
    T2 second;
};

Map有两个元素,使用的就是pair类型。

4.3 插入操作
代码语言:javascript
复制
pair<string, string> k1("a", "A");
map<string, string> ma = { 
    k1,                                // 1. 构造pair有名对象插入k1
    pair<string, string>("b", "B"),    // 2. 匿名对象
    make_pair("c", "C"),               // 3. make_pair函数返回pair类型
    {"d", "D"}                         // 4. 初始化列表
};
4.4 插入重复值
代码语言:javascript
复制
ma.insert({ "a", "B" });  // 依旧是原来的,不会更新

4.5 遍历方法

范围for循环

代码语言:javascript
复制
for (auto& e : ma)
{
    cout << e.first << ":" << e.second << endl;
}

迭代器遍历

代码语言:javascript
复制
auto it = ma.begin();
while(it != ma.end())
{
    cout << it->first << ":" << it->second << endl;
    it++;
}

// 本质:
while(it != ma.end())
{
    cout << it.operator->()->first << ":" << it.operator->()->second << endl;
    it++;
}
// 取出pair的指针,再指向first
4.6 key不可变,val可变
代码语言:javascript
复制
// ma.begin()->first = "a";   // 错误,key不可修改
ma.begin()->second = "a";     // 正确,value可以修改
4.7 []运算符重载
代码语言:javascript
复制
map<int, int> ma2;
ma2[2]++;  // []有三重含义:插入、查找、修改

[]运算符的功能

  1. 有key这个值:查找key并修改value
  2. 没key这个值:查找key并插入(value使用默认值)

可以充当insert的功能。

4.8 insert返回值
代码语言:javascript
复制
pair<map<string,string>::iterator, int> r1 = ma.insert({ "a","B" });
pair<map<string, string>::iterator, int> r2 = ma.insert({ "e","E" });

cout << r1.second << ":" << r1.first->first << endl;  // 失败:0:a
cout << r2.second << ":" << r2.first->first << endl;  // 成功:1:e
  • 成功:返回pair<迭代器, true>
  • 失败:返回pair<已存在的迭代器, false>

注意,这个pair和插入的pair不是同一个。

5. Multimap

与map的主要区别:

  1. 每次插入一定成功(允许重复key)
  2. erase操作:mmp.erase("a"); 将删除所有key为"a"的pair
  3. 不支持[]运算符的修改功能
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 序列式容器和关联式容器
  • 2. Set的使用
    • 2.1 概况
    • 2.2 主要特点
    • 2.3 去重与打印
    • 2.4 仿函数的使用
    • 2.5 初始化列表初始化
    • 2.6 删除操作
    • 2.7 查找操作比较
    • 2.8 count函数
    • 2.9 lower_bound和upper_bound
    • 3.1 查找操作
    • 3.2 删除操作
  • 4. Map的使用
    • 4.1 概况
    • 4.2 Pair结构
    • 4.3 插入操作
    • 4.4 插入重复值
    • 4.6 key不可变,val可变
    • 4.7 []运算符重载
    • 4.8 insert返回值
  • 5. Multimap
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档