map和set的使用

news2024/12/24 11:41:27

文章目录

      • 关联式容器
      • 树形结构的关联式容器
        • set
          • insert增减
          • erase删除
          • multiset
          • 修改
        • map
          • pair<key,value>
          • insert
          • operator[] 的引入
          • insert和operator[]的区别
          • multimap
        • 小结
        • map的使用
          • 统计最喜欢吃的前几种水果
          • 前K个高频单词,返回单词的频率由高到低,频率相同时,字典序排列

关联式容器

  • 序列式容器: vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身,元素之间无关系,可以随意的插入.

  • 关联式容器:map/set… 存储加查找数据,数据之间不能随便插入和删除,有强烈的关联关系.关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高

    • 键值对

      用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义.

树形结构的关联式容器

set

底层是之前实现过的搜索树的K模型

insert增减

搜索树走得是中序遍历,BS搜索树是底层,自身带有排序+去重的功能。
如果有相同的值就不会进行再次插入的了。
所以有去重的需要可以用set,默认是升序.

erase删除

删除某一个元素,要先进行查找,就是find()

  • 删除一个位置和删除一个值的区别:

位置要确保位置的有效,而删除值有就删除没有就没有反馈。

  • erase的返回值是已经删除的指定元素的个数
void test_set()
{
	set<int> st;
	st.insert(3);
	st.insert(5);
	st.insert(4);
	st.insert(2);
	st.insert(8);
	st.insert(9);
	st.insert(9);
	//迭代器
	set<int>::iterator it = st.begin();
	while (it != st.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;//2 3 4 5 8 9

	set<int>::iterator pos = st.find(3);
	if (pos != st.end())
	{
		st.erase(pos);
	}
	//有序说明搜索树走得是中序-排序
	//去重效果:相同数据插入失败
//范围for
	for (auto e : st)
	{
		cout << e << " ";
	}
	cout << endl;
}
multiset

如果只想排序,不想要去重就用:multiset (多样的)

当删除的值有多个的时候,删除的值是哪一个位置的呢?

  • find查找到的是中序的第一个,也就是最左节点.
void test_multi_set()
{
	multiset<int>st;
	st.insert(3);
	st.insert(5);
	st.insert(4);
	st.insert(2);
	st.insert(8);
	st.insert(9);
	st.insert(9);
	st.insert(9);
	st.insert(9);
	st.insert(9);
	st.insert(1);
	multiset<int>::iterator  it = st.begin();
	while (it != st.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	auto pos = st.find(9);
	while (pos != st.end())
	{
		cout << *pos << " ";
		++pos;
	}

	//如何将所有重复元素删除
	//auto pos1 = st.find(9);
	//while (pos1 != st.end() && *pos1 == 9)
	//{
	//	st.erase(pos1);
	//	//节点指针被干掉之后是野指针无法++,所以会崩溃
	//	++pos1;
	//}

	cout << st.erase(9) << endl;//把所有9都删了,还返回了删了几个

	for (auto e : st)
	{
		cout << e << " ";
	}
	cout << endl;
}
修改

运用迭代器进行修改的时候是不允许的,因为改动某一个节点的值之后就可能不是搜索树,因为节点之间存在大小关系.

image-20230301104723404

map

底层是搜索树对应的key-val模型

image-20230301114942680

pair<key,value>

image-20230301110508785

  • pair<>提供构造函数

    image-20230301110950797

  • pair<>匿名对象

  • make_pair()函数模板,对匿名对象的一层封装.虽然看起来多一层函数调用,其实可以设置为内联函数直接打开.

image-20230301105953279

pair是一个结构体,两个值都是公有的.

pair并没有重载流插入和流提取运算符,遍历的时候可以通过first和second进行访问.

void test_map()
{
	map<string,string>m;
	//pair的构造函数
	pair<string, string> kv1("sort", "排序");
	m.insert(kv1);
	//pair的匿名对象
	m.insert(pair<string,string>("string","字符串"));
	//make_pair自动推导类型,简洁
	m.insert(make_pair("test","测试"));

	map<string, string>::iterator it = m.begin();
	while (it != m.end())
	{
		//cout << *it << endl;
		//pair不支持流插入和流提取
		cout << (*it).first << ":" << (*it).second << endl;
		cout << it->first << ":" << it->second << endl;
		++it;
	}
	cout << endl;

	//最好加上&,因为每一次pair中的string都得拷贝给e
	for (auto& e : m)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
}

map的key不支持修改,但是val是支持修改的.因为搜索树的关系是靠key来维护的.

insert

插入的时候涉及到去重需要先进行查找,由于是搜索树插入的时候为了更合适的位置又进行了一遍查找
为了进行优化,引进了pair(iterator,bool) insert();实现用iterator和bool两个标志来完成对于上面的优化。

image-20230301114646727

void test_map2()
{
	//了解insert返回值之前
	string arr[] = {"苹果","苹果", "苹果", "苹果", "苹果", "香蕉","西红柿"};
	map<string, int> countMap;
	for (auto& str : arr)
	{
		auto ret = countMap.find(str);
		if (ret == countMap.end())
			countMap.insert(make_pair(str, 1));
		else
			ret->second++;
	}
	//了解insert返回值之后
	for (auto& str:arr)
	{
		auto kv = countMap.insert(make_pair(str,1));
		if (kv.second == false)
		{
			kv.first->second++;//返回值的第一个是相同节点的指针
		}
	}
    //[]的引入
	for (auto& str : arr)
	{
		countMap[str]++;
	}

	for (auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	cout << endl;
}
operator[] 的引入

image-20230301114548560

迭代器要么指向新插入的节点要么指向相同值的节点.

//map中[]的文档注释
mapped_type& operator[](const key_type& k)
{
	return *(this->insert(make_pair(k,mapped_type())).first).second;
}
//帮助理解版本
mapped_type&operator[](const key_type& k)
{
	pair<iterator,bool> ret=insert(make_pair(k,mapped_type()));
	return ret->first.second;
}

image-20230301115330829

水果第一次出现,插入+修改,insert时考虑的只有key.

水果不是第一次出现,查找+修改,因为&的存在,作用在相同值节点的second上.

insert和operator[]的区别

image-20230301120831909

image-20230301120943611

multimap
  • 允许key冗余,multimap 类型。无论是否相同都会进行插入.

  • 不支持[]的出现根据底层理解,应该返回哪个节点的value值呢?

  • cout<<dict.count(“left”);返回key出现的次数.

小结

前面对map/multimap/set/multiset进行了简单的介绍,在介绍中发现,这几个容器有个共同点是:其底层都是按照二叉搜索树来实现的,但是二叉搜索树有其自身的缺陷,假如往树中插入的元素有序或者接近有序,二叉搜索树就会退化成单支树,时间复杂度会退化成O(N),因此map、set等关联式容器的底层结构是对二叉树进行了平衡处理,即采用平衡树来实现。

map的使用

统计最喜欢吃的前几种水果
# include<algrithm>

struct CountVal
{
	bool operator()(const pair<string ,int>&l,const pair<string,int>&r)
	{
		//return l.second >r.second;
		return l.second < r.second;//堆,优先级队列中使用的
	}
}
struct CountIterator
{
	bool operator()(const map<string,int>::iterator& l,const map<string,int>::iterator&r)
	{
		//return l->second>r->second;
		return l->second< r->second;//优先级队列中使用的,想要建立的是一个大堆
	}
}
void GetfavoriteFruit(const vector<string>&fruits,size_t k)
{
	map<string,int>countmap;
	for(auto &e:countmap)
	{
		countmap[e]++;
	}
	//数据量不大的排序
	//sort,为了便于进行以次数为依据的排序,需要先将数制拷贝到数组中进行排序。
    
//1. 第一种写法:有很多次对于pair类型的深拷贝放到vector中,如果string很长就是浪费空间
	vector<pair<string,int>> sortV;
	for(auto &kv: countmap)
	{
		sortV.push_back(kv);
	}
	sort(sortV.begin(),sortV.end(),CountVal());
    for(int i=0;i<k;i++)
    {
        cout<<sortV[i].first<<":"sortV.second<<endl;
    }
    cout<<endl;

//2. 第二种写法,vector的迭代器支持排序,而map的不支持
//那么就将pair的迭代器拷贝进vector中
    vector<map<string,int>::iterator> sortV;
    auto it = countmap.begin();
    while(it!=countmap.end())
    {
        sortV.push_back(it);
        ++it;
    }
    sort(sortV.begin(),sortV.end(),CountIterator());

    for(int i=0;i<k;i++)
    {
        cout<<sortV[i]->first<<":"<<sortV[i]->second<<endl;//容器当中都是迭代器

    }
    cout<<endl;
//3. 使用multimap<>操作
//仿函数默认是升序less,将他设置为greater就改成了降序
//头文件
#include<functional>
    multimap<int ,string,greater<int>> sortmap;
    for(auto &kv:countmap)
    {
        sortmap.insert(make_pair(kv.second,kv.first));//根据value排序
    }
//4.1 用优先级队列,用的是堆
//#include<queue>
	priority_queue<pair<string,int>,vector<pair<string,int>>,CountVal> pq;
    //pq这里类模板传类型CountVal,前两种仿函数是函数模板传对象CountVal()
    for(auto&kv;countmap)
    {
        pq.push(kv);
    }
    while(k--)
    {
        cout<<pq.top().first<<" :"<<pq.top().second<<endl;
        pq.pop();
    }
    cout<<endl;

//4.2 没有必要将数据也拷贝出来,拷贝迭代器出来就可以找到相应的数据
 priority_queue<map<string,int>::iterator,vector<map<string,int>::iterator>,CountIterator> pq;
    auto it=countmap.begin();
    while(it!=countmap.end())
    {
        pq.push(it);
        ++it;
    }
    while(k--)
    {
        cout<<pq.top()->first<<" :"<<pq.top()->second<<endl;
        pq.pop();
    }
        cout<<endl;
}
//pair 是支持比较大小的。


  • 注意参数(类型,承装类型的容器,仿函数)
  • 优先级队列,小于建的是大堆

image-20230301165627758

前K个高频单词,返回单词的频率由高到低,频率相同时,字典序排列

sort的底层是快排,是不稳定的排序。只有稳定的排序才能保证字典序i在L的前面.稳定的排序:stable_sort()

//使用map的特性
vector<string>topKFrequency(vector<int>&words,int k)
{
	map<string,int> countmap;
	for(auto& kv : words)
	{
		countmap[kv]++;
	}
    multimap<int ,string,greater<int>> sortMap;
    for(auto & kv: countmap)
    {
        sortMap.insert(make_pair(kv.second,kv.first));
    }
    vector<string>v;
    auto it=sortMap.begin();
    while(k--)
    {
        v.push_back(it->second);
        ++it;
    }
    return v;
}

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

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

相关文章

Isaac-gym(9):项目更新、benchmarks框架梳理

一、项目更新 近期重新git clone isaac gym的强化部分&#xff08;具体见系列第5篇&#xff09;时发现官方的github库有跟新&#xff0c;git clone下来后发现多了若干个task&#xff0c;在环境配置上也有一定区别。 例如新旧两版工程项目的setup.py区别如下&#xff1a; git …

现在的00后太强了,几个问题差点给我问懵了

前言 我们公司刚入职一个00后小伙&#xff0c;今天在办公室交流了一下&#xff0c;他问我会不会自动化测试&#xff0c;我说懂一点&#xff0c;然后直接问了我几个自动化测试问题&#xff0c;差点直接给我问懵了&#xff01; 问题如下&#xff1a; 我们在制定自动化测试实施…

计算机组成原理4小时速成5:输入输出系统,io设备与cpu的链接方式,控制方式,io设备,io接口,并行串行总线

计算机组成原理4小时速成5&#xff1a;输入输出系统&#xff0c;io设备与cpu的链接方式&#xff0c;控制方式&#xff0c;io设备&#xff0c;io接口&#xff0c;并行串行总线 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c…

刷题笔记1 | 704. 二分查找,27. 移除元素

704. 二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 …

备战蓝桥杯——sort函数

备战蓝桥杯——sort函数排列字母lambda匿名函数排列字母 链接: 排列字母 不用多说&#xff0c;很简单的签到题&#xff0c;我们先来了解一下sort函数的用法 list.sort(cmpNone, keyNone, reverseFalse) cmp:进行比较的方法&#xff08;可以自定义排序的方法&#xff0c;通常…

vue2前端实现html导出pdf功能

1. 功能实现方案 1.html转换成canvas后生成图片导出pdf&#xff08;本文选用&#xff09; html转canvas插件&#xff1a;html2canvas是一款将HTML代码转换成Canvas的插件&#xff1b;canvas生成pdf&#xff1a;jsPDF是一个使用Javascript语言生成PDF的开源库 2.HTML代码转出…

JavaWeb详解加实战

JavaWeb 1、基本概念 1.1、前言 web开发 web&#xff0c;网页的意思静态web HTML、CSS提供给所有人看的数据始终不变 动态WEB 提供给所有人看的数据始终会发证变化&#xff0c;每个人在不同的时间&#xff0c;地点看到的信息各不相同技术栈&#xff1a;Servlet/JSP&#xf…

LeetCode 热题 HOT 100 Java 题解 -- Part 2

练习地址 Part 1 : https://blog.csdn.net/qq_41080854/article/details/128829494 LeetCode 热题 HOT 100 Java 题解 -- Part 236. 二叉树的中序遍历 9437. 不同的二叉搜索树 9638. 验证二叉搜索树 9839. 对称二叉树 10140. 二叉树的层序遍历 10241. 二叉树的最大深度 10442.…

cycleGAN算法解读

本文参考&#xff1a;https://blog.csdn.net/Mr_health/article/details/112545671 1 CycleGAN概述 CycleGAN&#xff1a;循环生成对抗神经网络&#xff0c;是一种非监督学习模型。 Pix2pix方法适用于成对数据的风格迁移&#xff0c;而大多数情况下对于A风格的图像&#xf…

vue样式绑定(v-if)

文章目录一.第一次用vue框架二.要求:1.定义两种样式&#xff0c;一种描述正确的状态&#xff0c;一种描述错误的状态。2.在结构代码中定义一个块&#xff0c;实现绑定正确的样式状态。3.定义一个按钮&#xff0c;实现正确和错误两种状态的class切换。三.源代码四.效果一.第一次…

极客之选:用Rollup打包工具优化前端代码,让你成为前端领域的高手

前端开发面临着不断变化的技术和越来越复杂的项目需求&#xff0c;如何优化前端代码成为了前端开发人员必须要面对的挑战。本论文介绍了一个名为Rollup的打包工具&#xff0c;该工具可以帮助开发人员优化前端代码&#xff0c;减小代码体积&#xff0c;提高网站性能。本论文将介…

那些年用过的IDEA插件

今天和大家分享一下经常使用的IDEA的插件&#xff0c;希望有所帮助。一、IDEA插件CodeGlance2显示代码缩略图插件&#xff0c;方便查看代码。Lombok用于编译期间自动生成getter、setter、构造、toString等方法&#xff0c;简化代码。Mybatis Builder或MybatisXMapper接口和xml双…

2023雅虎邮箱不能注册?别急,这份教程教你成功注册雅虎邮箱

这几年&#xff0c;跨境电商的迅猛发展&#xff0c;越来越多人加入这片蓝海&#xff0c;跨境人拥有一个专业的邮箱账户显得尤为重要&#xff0c;它是商业交流和日常工作的必备工具。因此&#xff0c;雅虎邮箱成为了许多人的首选&#xff0c;全球范围内使用雅虎邮箱的人数是非常…

问题三十二:离散二维傅立叶变换(Discrete Fourier Transformation)

为了将灰度图像表示为频谱图&#xff0c;我们需要进行以下步骤&#xff1a; 加载图像并将其转换为灰度图像。对图像进行二维离散傅里叶变换。将变换结果表示为幅度谱和相位谱。可以对幅度谱和相位谱进行可视化&#xff0c;以查看频率分布。对幅度谱和相位谱进行逆变换&#xf…

做毕业设计,前端部分你需要掌握的6个核心技能

其实前端新手如果想要自己实现一套毕业设计项目并非简单的事&#xff0c;因为之前很多人一直还停留在知识点的阶段&#xff0c;而且管理系统和C端网站都需要开发&#xff0c;但现在需要点连成线了。所以在启动项目开发之前呢&#xff0c;针对前端部分&#xff0c;我列举一些非常…

react lazyLoad学习记录

react lazyLoad学习记录1.lazyLoad用处2.使用2.1 react-router-dom5版本写法2.2 react-router-dom6版本写法1.lazyLoad用处 默认例如首页&#xff0c;如果有好十几个甚至百个路由&#xff0c;react是会默认一下全部把路由组件一下全部加载的&#xff0c;极可能造成页面卡顿。r…

mysql数据库之sql语句性能分析工具

一、sql执行频率。 mysql客户端连接成功后&#xff0c;通过show [session | global] status 命令可以提供服务器状态信息。通过如下指令&#xff0c;可以查看当前数据库的INSERT/UPDATE/DELETE的访问频次。 #一个下划线代表一个字符 show global status like com_; 二、慢查…

冲鸭!33% 程序员月薪达到 5 万元以上~

2023年&#xff0c;随着互联网产业的蓬勃发展&#xff0c;程序员作为一个自带“高薪多金”标签的热门群体&#xff0c;被越来越多的人所关注。在过去充满未知的一年中&#xff0c;他们的职场现状发生了一定的改变。那么&#xff0c;程序员岗位的整体薪资水平、婚恋现状、职业方…

注意,摸鱼程序员常用的9个小技巧,早点下班不秃头

9个养生小技巧&#xff0c;祝大家不秃头嗨害大家好鸭&#xff01; 我是小熊猫~毕竟摸鱼一时爽&#xff0c;一直摸一直爽嘛~一、整理字符串输入二、迭代器切片&#xff08;Slice&#xff09;三、跳过可迭代对象的开头四、只包含关键字参数的函数 (kwargs)五、创建支持「with」语…

【C/C++】getchar()在处理字符输入时的一个细节

1、当我们进行“输入”后&#xff0c;无论输入一个字符或者是一个数字、一个字符串。都会自动产生一个换行符&#xff0c;而这个不起眼的回车符(‘\n’)也是一个‘字符’。如果我们需要连续多次输入‘字符’&#xff0c;则需要在每次输入字符后&#xff0c;及时处理这个换行符。…