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

目录

[1. 序列式容器和关联式容器](#1. 序列式容器和关联式容器)

[2. Set的使用](#2. Set的使用)

[2.1 概况](#2.1 概况)

[2.2 主要特点](#2.2 主要特点)

[2.3 去重与打印](#2.3 去重与打印)

[2.4 仿函数的使用](#2.4 仿函数的使用)

[2.5 初始化列表初始化](#2.5 初始化列表初始化)

[2.6 删除操作](#2.6 删除操作)

[2.7 查找操作比较](#2.7 查找操作比较)

[2.8 count函数](#2.8 count函数)

[2.9 lower_bound和upper_bound](#2.9 lower_bound和upper_bound)

[​编辑3. Multiset](#编辑3. Multiset)

[3.1 查找操作](#3.1 查找操作)

[3.2 删除操作](#3.2 删除操作)

[4. Map的使用](#4. Map的使用)

[4.1 概况](#4.1 概况)

[4.2 Pair结构](#4.2 Pair结构)

[4.3 插入操作](#4.3 插入操作)

[4.4 插入重复值](#4.4 插入重复值)

[​编辑4.5 遍历方法](#编辑4.5 遍历方法)

[4.6 key不可变,val可变](#4.6 key不可变,val可变)

[4.7 []运算符重载](#4.7 []运算符重载)

[4.8 insert返回值](#4.8 insert返回值)

[5. Multimap](#5. Multimap)


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

  • 序列式容器:逻辑结构为线性序列,交换数据后,性质依旧不变

  • 关联式容器:两个位置联系紧密,交换会破坏存储结构

2. Set的使用

2.1 概况

  • 底层结构:红黑树(平衡二叉搜索树)

  • 声明 :数据类型 + 仿函数 + 容器(后两个参数可有默认值)

  • 迭代器 :双向迭代器,通过中序遍历得到有序数组

  • 构造方式:与list类似

    • 默认构造

    • 迭代器范围构造

    • 拷贝构造

    • 初始化列表构造

2.2 主要特点

  • 有容量相关接口,但使用不多

  • 支持增(insert)、删(erase)、查(find)操作

  • 不支持修改,因为修改可能破坏红黑树性质

2.3 去重与打印

cpp 复制代码
set<int> se;
se.insert(2);
se.insert(2);
se.insert(5);

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

特点

  • Set会自动去重

  • 迭代器中序遍历,打印有序数组

2.4 仿函数的使用

cpp 复制代码
// 使用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 初始化列表初始化

cpp 复制代码
set<int> se;
se.insert({ 2,8,3,9,2 });

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

2.6 删除操作

删除最小值

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

删除指定值

cpp 复制代码
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 查找操作比较

cpp 复制代码
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函数

cpp 复制代码
// 返回值的个数(在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:找第一个>指定值的元素

cpp 复制代码
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 查找操作

cpp 复制代码
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 删除操作

cpp 复制代码
mset.erase(4);  // 删除所有值为4的元素
// erase也可以传迭代器,并返回新的迭代器

4. Map的使用

4.1 概况

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

4.2 Pair结构

cpp 复制代码
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 插入操作

cpp 复制代码
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 插入重复值

cpp 复制代码
ma.insert({ "a", "B" });  // 依旧是原来的,不会更新

4.5 遍历方法

范围for循环

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

迭代器遍历

cpp 复制代码
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可变

cpp 复制代码
// ma.begin()->first = "a";   // 错误,key不可修改
ma.begin()->second = "a";     // 正确,value可以修改

4.7 []运算符重载

cpp 复制代码
map<int, int> ma2;
ma2[2]++;  // []有三重含义:插入、查找、修改

[]运算符的功能

  1. 有key这个值:查找key并修改value

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

可以充当insert的功能。

4.8 insert返回值

cpp 复制代码
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. 不支持[]运算符的修改功能

相关推荐
蒜丶2 小时前
基于 frp 0.65 tcp 模式,实现web服务&ssh服务内网穿透
网络
Kiyra2 小时前
LinkedHashMap 源码阅读
java·开发语言·网络·人工智能·安全·阿里云·云计算
A13247053122 小时前
防火墙配置入门:保护你的服务器
linux·运维·服务器·网络
计算机小手3 小时前
Kong + Konga 网关入门实践:Docker 部署、反向代理与插件使用指南
运维·经验分享·网络协议·docker·kong·开源软件
汪碧康4 小时前
【k8s-1.34.2安装部署】六.企业级部署cilium-1.18.4网络插件
网络·云原生·容器·kubernetes·k8s·cilium·xkube
博语小屋4 小时前
TCP:协议、序列化与反序列化、JSON 数据和jsoncpp
linux·网络·网络协议·tcp/ip·json
咸鱼2.04 小时前
【java入门到放弃】网络
java·开发语言·网络
wniuniu_4 小时前
blob是啥
java·服务器·网络