【C++】map 与 set 的介绍与使用

news2024/9/24 1:19:00

目录

一、关联式容器

二、键值对

三、set

3.1 set 的介绍

3.2 set 的使用

3.3. set 的使用举例

四、map

4.1 map的介绍

3.2 map 的使用

4.3 map的使用举例

五、经典练习题

1.set的使用

2.map的使用

思路一(稳定排序):

思路二(priority_queue):


一、关联式容器

在之前,我们接触过 vector、list、deque……,这些容器被称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那么什么是关联式容器呢?

关联式容器:关联式容器也是用来存储数据的,与序列式容器不同的是,其中存储的是<key,value>结构的键值对,在数据检索时比序列式容器效率更高。

二、键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量 key 、value。

key代表键值,value 表示与 key 对应的信息。比如:现在要建立一个英汉互译的字典,那该字典必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该英文单词,在字典中就可以找到其对应的中文含义。

SGI-STL中关于键值对的定义:

template <class T1, class T2>
struct pair
{
    typedef T1 first_type;
    typedef T2 second_type;
    T1 first;
    T2 second;

    pair()
        :first(T1()), second(T2())
    {}

    pair(const T1& a, const T2& b)
        :first(a), second(b)
    {}
};

三、set

3.1 set 的介绍

这里是 set 的文档介绍:set的介绍_C++reference 以下是几个重要点。 

  1. set 是按照一定次序存储的容器
  2. 在 set 中,元素的 value 也标识它(value 就是 Key,类型为 T),并且每个 value 必须是唯一的。set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  3. 在内部,set 中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。
  4. set 容器通过 key 访问单个元素的速度通常比 unordered_set 容易慢,但它们允许根据顺序对子集进行直接迭代。
  5. set 在底层是用二叉搜索树(红黑树)实现的。

3.2 set 的使用

1. set 的模板参数列表

T:set 中存放元素的类型,实际在底层存储<value,value>的键值对。

Compare:set 中元素默认按照小于来比较。

Alloc:set 中元素空间的管理方式,使用STL提供的空间配置器管理。

2. set 的构造函数

 3. set 的迭代器

iterator begin() 返回 set 中起始位置的迭代器
iterator end()返回 set 中最后一个元素的迭代器
iterator rbegin()返回第一个元素的迭代器,即end()
iterator rend()返回最后一个元素的迭代器,即begin()

4. set 的修改操作

函数声明功能介绍
pair<iterator,bool> insert (const value_type& x)

在set中插入元素x,实际是插入<x,x>构成的键值对,如果插入成功,返回<该元素在set中的位置,true>,如果插入失败,说明x在set中已经存在,返回<x在set中的位置,false>

void erase ( iterator position )
删除 set position 位置上的元素
size_type erase ( const key_type& x )
删除 set 中值为 x 的元素,返回删除的元素的个数
void erase ( iterator fifirst, iterator last )
删除 set [first, last) 区间中的元素
void clear ( )
set 中的元素清空
iterator find ( const key_type& x ) const
返回set中值为x的元素的位置,不存在返回end()
size_type count ( const key_type& x ) const
返回set中值为x的元素个数(multiset中使用)

3.3. set 的使用举例

四、map

4.1 map的介绍

map的文档简介 以下是几个重要点:

  1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和唯一的标识元素,而值value中存储与此key关联的内容。简直key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取名别称为pair
  3. 在内部,map中的元素总是按照及那只key进行排序的。
  4. map中通过简直访问但各国元素的熟读通常比unordered_map容器慢,但map允许根据顺序对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)
  5. map支持下标访问操作符,即在[]中放入key,就饿可以找到与key对应的value。
  6. map通常被实现为二叉搜索树(准确的说是红黑树)

3.2 map 的使用

1.map的模板参数说明

  •  key:键值对中key的类型
  • T:键值对中value的类型
  • Compare:比较器的类型。默认为less,如果存在特殊的比较,需要用户自己显示传入比较规则(函数指针或仿函数进行传递)

2.map的构造函数

 3.map的迭代器

iterator begin() 返回 map 中起始位置的迭代器
iterator end()返回 map 中最后一个元素的迭代器
iterator rbegin()返回第一个元素的迭代器,即end()
iterator rend()返回最后一个元素的迭代器,即begin()

4.insert

首先我们来看看insert的使用,首先要知道map的insert是插入pair类型的数据

 然后我们举例进行插入一下

void test_map1()
{
	//创建字典
	map<string, string> dict1;
	map<string, string> dict2;
	map<string, string> dict3;
	//插入数据——方式1、
	pair<string, string> kv1("sort", "排序");
	pair<string, string> kv2("insert", "插入");
	dict1.insert(kv1);
	dict1.insert(kv2);

	//插入数据——方式2、匿名对象
	dict2.insert(pair<string, string>("sort", "排序"));
	dict2.insert(pair<string, string>("insert", "插入"));

	//插入数据——方式3、make_pair()
	dict3.insert(make_pair("sort", "排序"));
	dict3.insert(make_pair("insert", "插入"));
}

插入方式3,make_pair其实是一个模板函数,就是为了方便我们进行pair结构的插入数据。

4. 下标访问操作符

这里我们实现一个统计水果次数功能的map,如下:

 但是这样的插入方式,非常的麻烦,所以map将下标访问操作符进行了重载,让其插入数据变得十分轻松。以下是 map中下标访问操作符:

功能解析:

  1. map中有这个key,返回value的引用。(查找、修改value)
  2. map中没有这个key,会插入pair(key,V()),并返回value的引用。(插入+修改)

其实下标访问操作符的本质是调用了 insert 函数,下面的文档中的实现方式:

这种方式其实不是太好理解,这里我们可以将其分为两步,就非常好理解了。

4.3 map的使用举例

因为返回的是其value的引用,所以我们可以对其进行赋值,这也是一种插入方式,也是最简单的一种插入方式。

 所以,在上面实现统计水果次数的map中,我们可以将其插入方式改为 [] 插入:

五、经典练习题

1.set的使用

题目链接:349. 两个数组的交集

题目介绍:

算法思路1:

  1. 因为是求交集,所以我们可以使用set对nums1、nums2进行排序+去重。
  2. 遍历set1,判断set1中的值是否存在于set2中,如果存在,则放到结果数组中,不存在则跳过(时间复杂度:O(N*N))。

算法思路2:

  1. 因为是求交集,所以我们可以使用set对nums1、nums2进行排序+去重。
  2. 同时处理两个区间,让it1指向的值与it2指向的值进行比较,如果相等则为交集,两个迭代器同时向后移动,如果不相等,结果小的迭代器进行向后移动(时间复杂度:O(N))

两种算法就是找交集的代码不同,这里一并给出源代码:

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        set<int> s1;
        set<int> s2;
        //去重  
        for(auto& e: nums1)
            s1.insert(e);
            
        for(auto& e: nums2)
            s2.insert(e);
        //找交集
        vector <int >result;
        //方法1:
        for(auto& e: s1)
        {
            if (s2.find(e)!=s2.end())
                result.push_back(e);
        }
        //============================================
        //方法2:
        set<int>::iterator it1=s1.begin();
        set<int>::iterator it2=s2.begin();
        while(it1!=s1.end()&&it2!=s2.end())
        {
            if (*it1==*it2)
            {
                result.push_back(*it1);
                it1++,it2++;
            }
            else if (*it1>*it2) it2++;
            else it1++;
        }
        return result;
    }
};

2.map的使用

题目链接:692. 前K个高频单词

题目介绍:

这题的难点就在于出现频率相等的情况下,要按照字典序排序,这就意味着不能简单的使用一次排序解决。

思路一(稳定排序):

算法思路:

  1. 使用map根据其字典序进行排序,并统计单词的出现次数。
  2. 通过sort根据单词的出现次数进行排序。

使用了map存储后,单词在map中都按出现次数进行排序,但是此时,如果我们使用一种稳定排序,让其在符合次数相同时,并进行字典序的排序,就可以完成最终的排序。

首先 sort 是一个的迭代器是随机迭代器(RandomAccess Iterator),而map双向迭代器(bidirectional iterator),所以我们要先将map中的数据放入到一个数组中。

 因为sort是快速排序,不稳定的排序,所以我们要编写仿函数控制其排序的结果。

 仿函数的比较规则:

  1. 如果出现次数多,则排在前面,返回true。
  2. 出现次数相同时再比较字典序,如果kv1的字典序小于kv2,即kv1在kv2前,则返回true,编写这条规则可以间接控制稳定性。
  3. 其他情况直接返回false。
class Solution {
public:
    struct Greater{
        bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)
        {
            //按次数比较
            if (kv1.second > kv2.second)
                return true;
            //次数相同,按字典序比较。
            if (kv1.second==kv2.second&&kv1.first < kv2.first)
                return true;
            return false;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(auto& str:words)
        {
            countMap[str]++;
        }
        //导数据,因为迭代器类型不同
        vector<pair<string,int>> sortV(countMap.begin(),countMap.end());
        sort(sortV.begin(),sortV.end(),Greater());

        vector <string> result;
        for(int i=0;i<k;i++)
        {
            result.push_back(sortV[i].first);
        }
        return result;
    }
};

因为map中已经按照字典序进行了排序,所以我们只需要使用一种稳定的排序,将出现次数多的调整到前面,出现次数相同则不进行调整。

库中的稳定排序(stable_sort):

 进行以下修改即可:

思路二(priority_queue):

算法思路:

  1. 使用map根据其字典序进行排序,并统计单词的出现次数。
  2. 再将数据放入priority_queue中,通过自定义仿函数建立k的数的小堆。
  3. 再将前k个数放入结果数组中。

既然要使用我们自己的仿函数,则模板参数这我们要额外注意,我们要按顺序传入参数,在仿函数前要先传入存储容器,因为此题使用的vector进行的存储,所以直接传入vector即可。

注意,第三个仿函数参数我们直接传入仿函数名即可,因为我们自己实现的仿函数一般不会再设置模板。不要写浑了(hhh)。

 仿函数的比较规则:

 我们想每次在堆顶取出 出现次数最多并且字典序小的数据,所以如果child出现次数多则往上调整,或出现次数相同字典序位于前的,进行往上调整,每次取出堆顶数据再弹出堆顶,则结果可按照我们想要的顺序进行排序。

  1. kv2的出现次数多则往上调整返回true。
  2. 出现次数相同时再比较字典序,字典序如果kv1大于kv2,则kv2在字典序前面,进行向上调整,则返回true。
  3. 其他情况直接返回false。
struct Less {
	bool operator()(const pair<string, int>& kv1, const pair<string, int>& kv2)
	{
		//按次数比较
		if (kv1.second < kv2.second)
			return true;
		//次数相同,按字典序比较。
		if (kv1.second == kv2.second && kv1.first > kv2.first)
			return true;
		return false;
	}
};

然后我们将数据插入到priority_queue中,我们可以使用迭代器区间进行初始化,也可以直接push插入数据。

因为要返回前k的数据。所以使用while循环,在priority_queue中取出前k个top数据,将其pair中的first放入结果数组中。

class Solution {
public:
    struct Less{
        bool operator()(const pair<string,int>& kv1,const pair<string,int>& kv2)
        {
            //按次数比较
            if (kv1.second<kv2.second)
                return true;
            //次数相同,按字典序比较。
            if (kv1.second==kv2.second&&kv1.first>kv2.first)
                return true;
            return false;
        }
    };
    vector<string> topKFrequent(vector<string>& words, int k) {
        map<string,int> countMap;
        for(auto& str:words)
        {
            countMap[str]++;
        }
        //迭代器区间初始化
        priority_queue <pair<string,int>,vector<pair<string,int>>,Less> 
        maxHeap(countMap.begin(),countMap.end());
        vector<string> result;
        while(k--)
        {
            result.push_back(maxHeap.top().first);
            maxHeap.pop();
        }
        return result;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LabVIEW使用共享变量在两台计算机之间进行通信

LabVIEW使用共享变量在两台计算机之间进行通信 需要选择一台计算机作为服务器并发布变量&#xff0c;而另一台计算机作为客户端接收变量。然后&#xff0c;按照以下步骤设置服务器和客户端计算机。 服务器机器&#xff1a; 创建LabVIEW项目并通过右键单击“我的电脑”并选择…

opencv-python常用函数解析及参数介绍(六)——图像梯度

图像梯度前言Sobel算子算子的定义Sobelx效果演示Sobely效果演示完整轮廓直接计算复杂图片的轮廓Scharr算子与laplacian算子scharr算子的定义laplacian算子定义三种算子的效果对比结尾前言 前面的文章中我们介绍了用膨胀和腐蚀得到了图像轮廓&#xff0c;图像梯度也是一种可以得…

五年六次

今天是 2022 年的最后一天&#xff0c;可算等来了。讽刺的是&#xff0c;就在昨天&#xff0c;小号写了篇文章&#xff0c;啥主题就不说了&#xff0c;然后晚上文章被删了&#xff0c;账号居然也被封了。2022 全年虽然我写过很多文章都被和谐了&#xff0c;但是最后一天喜提封号…

二、Django

Django 提示&#xff1a;本文根据b站黑马python课整理 链接指引 > 黑马程序员python企业级开发项目-手把手从0到1开发《美多商城》 文章目录DjangoMVT图解项目准备1.创建项目2.创建应用3.更换python解释器4.安装应用5.本地化6.项目中匹配urls7.应用中匹配urls.py8.准备视图…

Tensorflow游乐场 在线可视化

playground.tensorflow.org Tensorflow游乐场 Tensorflow游乐场提供了一个在线可视化AI训练。A Neural Network Playgroundhttp://playground.tensorflow.org/ Tensorflow游乐场 是干啥的呢 给一堆点分出蓝色部分和橙色部分。也就是二分类。 它提供了4种数据来训练 每种数据…

致敬客户、致敬行业,知道创宇2022“宇”你并肩前行!

2022回首2022&#xff0c;一幅数字化、智能化升级的壮阔云图徐徐展开&#xff0c;顺势催生出安全技术的全新变革……这一年&#xff0c;中国网络安全企业代表——知道创宇&#xff0c;持续从技术创新、安全服务、行业融合等方面深入网络安全产业升级。我们坚守攻防博弈战场、纵…

burp suite爆破sqli-labs的 less-5

一. 使用proxy抓包&#xff0c;具体数据包如下图&#xff1a; 二. 鼠标右键&#xff0c;将其发送到 intruder中&#xff0c;具体如下图&#xff1a; 三.选择下图选项卡&#xff1a; 1.默认为sniper模式&#xff0c;即如果有多个变量&#xff0c;对每个变量依次进行破解&#xf…

【 shell 编程 】第3篇 循环

循环 文章目录循环一、for 循环1.for 语法结构二、while、until 循环1.while 语法结构2.until 语法结构三、expect一、for 循环 1.for 语法结构 for 变量名 [ in 取值列表 ] do 循环体 done例子1 需求&#xff1a;自动循环创建10个用户 #&#xff01;/bin/bash read -p &quo…

【C++常用容器】STL基础语法学习set容器

目录 ●set构造和赋值 ●set大小和交换 ●set插入和删除 ●set查找和统计 ●set排序&#xff08;改变其排序规则&#xff0c;仿函数的运用&#xff09; ●set和multiset 1.对组&#xff08;pair&#xff09;的创建 2.set的验证&#xff08;不可以重复插入数据&#xff…

《QDebug 2022年12月》

一、Qt Widgets 问题交流 二、Qt Quick 问题交流 1、在 C 中关联 QQuickWindow 的 closing 信号提示 "使用了未定义类型QQuickCloseEvent" 因为 closing 信号中的参数类型是 private 模块中定义的&#xff0c;但是通过第二句提示我们知道找到了完整定义才能使用 Q_…

安装并配置uwsgi(1)

今天分享的主题是安装并配置uwsgi。 假设我们‍‍腾讯云主机里面的整个后端的源码&#xff0c;包括运行环境都已经没有问题了&#xff0c; 我们要把这个给挂到我们的 uwsgi 的服务器上&#xff0c; 因为这个服务器它支持 uwsgi 的协议&#xff0c;它能够跟我们的Django的进行一…

Shell——echo、printf及彩色打印

文章目录printfprintf格式常用的转义字符echoecho打印的格式echo打印的三种方式echo支持的转义字符关于打印叹号&#xff08;!&#xff09;彩色输出printf printf格式 printf “格式化字符串” 变量 printf的使用方法与C语言一样&#xff0c;并且不需要括号和逗号进行分隔&…

【自学Python】Python诞生

Python诞生 Python诞生教程 1989 年的圣诞节期间&#xff0c;吉多范罗苏姆为了在阿姆斯特丹打发时间&#xff0c;决心开发一个新的解释程序&#xff0c;作为 ABC 语言的一种继承。 ABC 语言是由吉多参加设计的一种教学语言&#xff0c;就吉多本人看来&#xff0c;ABC 这种语…

如何使用 Java Stream API ,一行代码将 List 转换为 Map 类型

文章目录一句话场景语法测试关键语句截图Source Code控制台输出一句话 List<User> --> Map<User对象中欲作为key的字段的类型, User> List<User> userList getUserList(); Map<Integer, User> idAndUserMap userList.stream().collect(Collecto…

2022朝花夕拾-持续快速成长

2022年又过去了&#xff0c;学业繁忙好久没和大家聊天了。2020年终总结2020朝花夕拾-不务正业的大学生做了什么比赛&#xff1f;和2021年终总结2021朝花夕拾-我在校搞副业实现经济独立在此&#xff0c;幸好去年立了年度目标。如今在回忆这一年的收获时&#xff0c;也可以一项项…

通过SQLserver执行系统命令

前言 咋说呢&#xff0c;就是把&#xff0c;我最近找工作然后库库投校招的简历&#xff0c;然后呢&#xff0c;我接到了一个青藤云的笔试机会&#xff0c;哇&#xff01;我激动的不行&#xff0c;然后我什么都没有准备的上线进行一波答题&#xff0c;答完总结下来&#xff0c;…

使用python实现跨年烟花代码

朋友们&#xff0c;有多久没放烟花了&#xff1f;今年你所在的地方允许放烟花么&#xff1f;既然我们不能线下放&#xff0c;那么我们就在线上放个够吧&#xff08;还是那句话&#xff1a;你~有~对~象~了~嘛~&#xff09; 一下是动态图&#xff08;图片我使用的我上几次的背景图…

算法设计与分析复习02:分而治之算法

算法设计与分析复习02&#xff1a;分而治之算法 文章目录算法设计与分析复习02&#xff1a;分而治之算法复习重点分而治之算法全排列递归算法矩阵乘法的Strassen算法棋盘覆盖线性时间选择复习重点 分而治之算法 全排列递归算法 #include<vector> #include<iostream&g…

await如何优雅的捕获异常?

传统方式 try { const res await getUser(id) }catch(err){console.log(err) } await让我们使用异步方式开发的代码简便不少&#xff0c;但是每次使用如果都用try..catch来捕获异常反而埋没了它的优势。 [ err, user ] await to(UserModel.findById(1)); 如果我们使用await…

CSS var() 自定义的属性值和使用

声明全局 CSS 变量 :root{<自定义属性名>: <自定义属性值>; }自定义属性名必需以 -- 开头。 :root :root 这个 CSS 伪类匹配文档树的根元素。对于 HTML 来说&#xff0c;:root 表示 <html> 元素&#xff0c;除了优先级更高之外&#xff0c;与 html 选择器…