C++——map和set的基本使用

news2024/12/23 17:54:39

目录

一,关联式容器

二,键值对

三,set的使用

3.1 set介绍

3.2 set的插入和删除

3.3 set的pair

3.4 multiset

四,map的使用

4.1 map介绍

4.2 map实现简易字典

 4.3 map实现统计次数

4.4 map的[]

五,使用map或set解决部分OJ题

5.1 复杂链表的复制

5.2 前K个高频单词

5.2.1 解法一:使用sort算法排序

5.2.2 使用multimap解决

 5.2.3 使用set的特性加仿函数解决

 5.3 两个数组的交集


一,关联式容器

在前面的文章里,我们以及接触过STL的部分容器,包括:vector,list,deque等,这些容器同称为序列式容器,因为其底层为线性序列的数据结构,里面存的是元素本身。

关联式容器也是用来存储数据的,与序列式容器不同,里面存储的式<key,value>结构的键值对,在数据检索时比序列式容器效率更高,关于键值对请看下面的内容

二,键值对

键值对是用来表示居于一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value。key代表监事,value表示与key对应的信息。比如建一个英汉互译的字典,所以这个字典中,英语单词与其含义是一一对应的关系,即通过该单词可以在字典中找到对应的中文含义

下面是STL中关于键值对pair的定义

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中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的

③在内部,set中的元素总是按照其内部比较对象所指示的特点排序准则进行排序

④set在底层是用红黑树实现的

3.2 set的插入和删除

void test_set1()
{
	//set<int> s = {1,2,1,6,3,8,5};//列表初始化
	int a[] = { 1,2,1,6,3,8,5 };
	set<int> s(a, a + sizeof(a) / sizeof(int));//set支持通过迭代器区间初始化
	//set<int,greater<int>> s(a, a + sizeof(a) / sizeof(int));可以自行控制这颗树

	//set间接完成了  排序+去重,因为set底层是一个搜索二叉树
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		//搜索树不允许修改key,可能会破坏搜索的规则
		//*it += 1;
		cout << *it << " ";
		it++;
	}
	cout << endl;
	//删除
	//方法1
	s.erase(1);
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;
	//方法2
	set<int>::iterator pos = s.find(2);
	if (pos != s.end())//判断有没有找到
	{
		s.erase(pos);
	}
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

	//count()返回数据个数,但由于set默认去重只能返回0或1,所以一般用作判断该数是否存在
	cout << s.count(3) << endl;  //判断在不在,并且返回个数
	cout << s.count(30) << endl;
}

 

void test_set2()
{
	set<int> myset;
	set<int>::iterator itlow, itup;
	for (int i = 0; i < 10; i++)
		myset.insert(i * 10);  //10 20 30 40 50 60 70 80 90
	itlow = myset.lower_bound(25);//返回的是>=val的第一个值,此处返回30
	itup = myset.upper_bound(60);//返回的是>val的第一个值,此处返回70
	cout << "[" << *itlow << "," << *itup << "]" << endl;

	myset.erase(itlow, itup);//删除这两个值所代表的范围之间的数
}

 

3.3 set的pair

void test_set3()//pair用来记录一对数据
{
	set<int> myset;
	for (int i = 1; i <= 5; i++)
		myset.insert(i * 10);//10 20 30 40 50 
	pair<set<int>::const_iterator, set<int>::const_iterator> ret;
	ret = myset.equal_range(40);

	cout << "the lower bound points to : " << *ret.first << endl;
	cout << "the upper bound points to : " << *ret.second << endl;
}

 

3.4 multiset

void test_multiset()//multiset与set不一样的是,multiset允许有重复值
{
	int a[] = { 3,1,2,1,6,3,8,3,5,3,1 };
	multiset<int> s(a, a + sizeof(a) / sizeof(int));

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

	cout << s.count(1) << endl;//这里的count就是记录个数了

	auto pos = s.find(3);
    //find时如果有多个值,返回中序的第一个位置,如果想找第二个3,把迭代器++一下就是第二个3
	while (pos != s.end())
	{
		cout << *pos << " ";
		++pos;
	}
	cout << endl;
	s.erase(3);//如果要删除的值有多个,删除所有的值
	for (auto e : s)
	{
		cout << e << " ";
	}
}

四,map的使用

4.1 map介绍

①map是关联容器,它按照特点的次序(按照key来比较)存储由简直key和value组合而成的元素

②在map中,键值key通常用于排序和唯一的标识元素,而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起,为其取别名称为pair

③在内部,map中的元素总是按照键值key进行比较排序的

④map支持下标访问符,即在[]中放入key,就可以找到与key对应的value

4.2 map实现简易字典

void test_map1()
{
	map<string, string> dict;
	pair<string, string> kv1("sort","排序");//隐式类型转换
	dict.insert(kv1);
	//但是上面有点麻烦,所以这时候“匿名对象”就排上用场了
	dict.insert(pair<string, string>("test", "测试"));
	dict.insert(pair<string, string>("string", "字符串"));

	typedef pair<string, string> DictkV;
	dict.insert(DictkV("string", "xxx"));//只看king相不相同,所以这里不用xxx替换“字符串”,king已经有了,所以直接插入失败
	//大家也不喜欢用typedef,喜欢用下面这个东东
	dict.insert(make_pair("left", "左边"));
	/*template<class T1,class T2>
	pair<T1, T2> make_pair(T1 x, T2 y)
	{
		return (pair<T1, T2>(x, y));
	}*/

	//map遍历
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	while (it != dict.end())
	{
		//cout << *it << endl;//报错,pair不支持流插入,迭代器的解引用是去调用operator*,set只有king就返回king的引用,pair有两个值first和secong,一个函数的调用用不允许返回两个值
		
		//cout << (*it).first << (*it).second << endl;虽然这样可以排序,但是map不喜欢这样搞
		cout << it->first << it->second << endl;//这里的it是指针,->经过重载,it->返回pari*,然后再->就可以找到first,但是就变成了it->->太难看了,所以编译器优化掉了一个->
		++it;
	}
	cout << endl;

	for (auto& kv : dict)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
}

 

 4.3 map实现统计次数

void test_map2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };
	//统计次数
	//map<string, int> countMap;
	//for(auto & str : arr)
	//{
	//	//map<string, int>::iterator it = countMap.find(str);
	//	//if (it != countMap.end()) //找到了
	//	//{
	//	//	//说明该水果是有的
	//	//	//(*it).second++;
	//	//	it->second++;
	//	//}
	//	//else //没找到
	//	//{
	//	//	//说明是一个新水果,插入一个
	//	//	countMap.insert(make_pair(str, 1));
	//	//}
	//}
	//上面的是常规的统计次数的方法,但是太麻烦了,我们一般用[]将查找插入修改一并完成
	map<string, int> countMap;
	for (auto& str : arr)
	{
		countMap[str]++; //重载的operator[]
		//1,str不在countMap中,插入pair(str,int()),然后再返回++                                   key已经在map中,返回pair(key_iterator,false);
		//2,str在countMap中,直接返回value的引用再++                                              key不在map中,返回pair(new_key_iterator,true);
	}
	map<string, int>::iterator it = countMap.begin();
	while (it != countMap.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}

	/*V& operator[](const K& key)
	{
		pair<iterator, bool> ret = insert(make_pair(key, V()); //insert完成了查找,bool表示插入是否成功
		return ret.first->second
	}*/
}

 

4.4 map的[]

void test_map3()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("count", "计数"));

	dict["left"];                   //插入 
	dict["right"] = "右边";         //插入+修改
	dict["string"] = "(字符串)";  //修改
	cout << dict["string"] << endl; //查找,打印 "(字符串)"

	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
}

五,使用map或set解决部分OJ题

5.1 复杂链表的复制

题目出处:LCR 154. 复杂链表的复制 - 力扣(LeetCode)

class Solution
{
public:
	Node* copyRandomList(Node* head)
	{
		map<Node*,Node*> copyNodeMap;
		Node* cur = head;
		Node* copyhead, *copytail;
		copyhead = copytail = nullptr;
		while (cur)
		{
			Node* copy = new Node(cur->val);
			copyNodeMap[cur] = copy;
			if (copytail == nullptr)
			{
				copytail = copyhead = copy;
			}
			else
			{
				copytail->next = copy;
				copytail = copytail->next;
			}
			cur = cur->next;
		}
		cur = head;
		Node* copy = copyhead;
		while (cur)
		{
			if (cur->random == nullptr)
			{
				copy->random = nullptr;
			}
			else
			{
				copy->random = copyNodeMap[cur->random];
			}
			cur = cur->next;
			copy = copy->next;
		}
		return copyhead;
	}
};

5.2 前K个高频单词

题目出处:692. 前K个高频单词 - 力扣(LeetCode)

5.2.1 解法一:使用sort算法排序

class Solution {
public:
	//比较大小仿函数
	struct Compare
	{
		bool operator()(const pair<string, int>& kv1, const pair<string, int>& kv2)
		{
			return kv1.second > kv2.second || kv1.second == kv2.second && kv1.first < kv2.first;
		}
	};
	vector<string> topKFrequent(vector<string>& words, int k) {
		map<string, int> countMap;
		for (auto& str : words)
		{
			countMap[str]++; //统计次数
		}
		//因为需要使用sort排序,而map是一个双向迭代器,不是随机迭代器也就是不能通过下标访问元素
		//所以我们先把值放进vector中排序
		vector<pair<string, int>> v(countMap.begin(), countMap.end());
		//stable_sort(v.begin(),v.end(),Compare()); //C++提供的稳定的排序函数
		sort(v.begin(), v.end(), Compare());
		vector<string> v1;
		for (size_t i = 0; i < k; i++)
		{
			v1.push_back(v[i].first);
		}
		return v1;
	}
};

5.2.2 使用multimap解决

class Solution {
public:
	/*struct Compare
	{
		bool operator()(const int& key1, const int& key2) const
		{
			return key1 > key2;
		}
	};*/
	vector<string> topKFrequent(vector<string>& words, int k) {
		map<string, int> countMap;
		for (auto& str : words)
		{
			countMap[str]++; //统计次数
		}
		//直接使用multimap进行排序
		//multimap<int, string, Compare> sortMap;
		multimap<int, string, greater<int>> sortMap; //巧合,题目给的测试用例插入的顺序刚好符合要求
		//当次数相同时,红黑树插入时插入在右边,如果插到左边就不行了
		for (auto& kv : countMap)
		{
			sortMap.insert(make_pair(kv.second, kv.first));
		}

		vector<string> ret;
		auto it = sortMap.begin();
		while (k--)
		{
			ret.push_back(it->second);
			++it;
		}
		return ret;
	}
};

 5.2.3 使用set的特性加仿函数解决

class Solution3 {
public:
	struct Compare
	{
		bool operator()(const pair<string, int>& kv1, const pair<string, int>& kv2) const
		{
			return kv1.second > kv2.second || kv1.second == kv2.second && kv1.first < kv2.first;
		}
	};
	vector<string> topKFrequent(vector<string>& words, int k) {
		map<string, int> countMap;
		for (auto& str : words)
		{
			countMap[str]++; //统计次数
		}
		//这里默认是升序,暂时我们要降序,所以加仿函数
		set<pair<string, int>, Compare> sortSet(countMap.begin(), countMap.end());
		vector<string> ret;
		auto it = sortSet.begin();
		while (k--)
		{
			ret.push_back(it->first);
			++it;
		}
		return ret;
	}
};

 5.3 两个数组的交集

题目出处:349. 两个数组的交集 - 力扣(LeetCode)

class Solution {
public:
	vector<int> intersection(vector<int>& nums1, vector<int>& nums2)
	{
		//先去重
		set<int> s1(nums1.begin(), nums1.end());
		set<int> s2(nums2.begin(), nums2.end());
		auto it1 = s1.begin();
		auto it2 = s2.begin();
		vector<int> ret;
		//前面完成了去重,不相等也就不是交集,小的值的迭代器++,相等,拿出相等值然后两个迭代器同时++
		while (it1 != s1.end() && it2 != s2.end())
		{
			if (*it1 < *it2)
			{
				it1++;
			}
			else if (*it2 < *it1)
			{
				it2++;
			}
			else
			{
				ret.push_back(*it1);
				it1++;
				it2++;
			}
		}
		return ret;
		//如果要找差集,那么相等时同时++,不相等,小的就是差集
		//如果一个走完了,另一个没有走完,那么没走完的剩下的值也是差集
	}
};

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

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

相关文章

CHS_01.2.1.1+2.1.3+进程的概念、组成、特征

CHS_01.2.1.12.1.3进程的概念、组成、特征 进程进程的概念 进程的组成——PCB进程的组成——PCB进程的组成——程序段、数据段知识滚雪球&#xff1a;程序是如何运行的&#xff1f;进程的组成进程的特征 知识回顾与重要考点 从这个小节开始 我们会正式进入第二章处理机管理相关…

暴雨信息发布算力网络应用平台打造零感知算网服务新模式

为进一步优化算力网络应用服务能力和降低算力网络使用难度&#xff0c;暴雨信息突破基于算力网络的实例跨域协同与迁移、基于测试评估的应用度量和解构等技术&#xff0c;研发并推出算力网络应用平台。该系统通过提供一种即开即用、按需付费的零感知算网应用服务&#xff0c;使…

捕捉小红书开年顶流,品牌快“跟风”上车!

2024年开年&#xff0c;“南方小土豆”纷纷北上&#xff0c;元旦期间哈尔滨收入近60亿元&#xff0c;“冰雪”一跃成为今冬最炙手可热的流行趋势&#xff01; 千瓜数据显示&#xff0c;小红书“冰雪”相关商业笔记同比去年增长649.84%。本期&#xff0c;千瓜将从“冰雪”场景出…

离散数学-二元关系

4.1关系的概念 1)序偶及n元有序组 由两个个体x和y&#xff0c;按照一定顺序排序成的、有序数组称为有序偶或有序对、二元有序组&#xff0c; 记作<x&#xff0c;y>&#xff0c;其中x是第一分量&#xff0c;y是第二分量。 相等有序偶&#xff1a;第一分量和第二分量分…

Excel·VBA按指定顺序排序函数

与之前写过的《ExcelVBA数组冒泡排序函数》不同&#xff0c;不是按照数值大小的升序/降序对数组进行排序&#xff0c;而是按照指定数组的顺序&#xff0c;对另一个数组进行排序 以下代码调用了《ExcelVBA数组冒泡排序函数》bubble_sort_arr函数&#xff08;如需使用代码需复制…

EasyPOI导出报表

报表导出是一种很常见的功能&#xff0c;只要是开发都会涉及到这一功能&#xff0c;早些年经常集成poi完成导出功能&#xff0c;我之前也有写过关于poi导出的文章&#xff0c;现如今&#xff0c;也有了更为方便的导出插件 — EasyPOI&#xff0c;废话不多说&#xff0c;开始撸代…

内网渗透实战攻略

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 介绍 什么是内网&#xff1f; 什么是内网渗透&#xff1f; 内网渗透的目的&#xff1a; 内网…

el-table实现多行合并的效果,并可编辑单元格

背景 数据为数组包对象&#xff0c;对象里面有属性值是数组&#xff1b;无需处理数据&#xff0c;直接使用el-table包el-table的方法&#xff0c;通过修改el-table的样式直接实现多行合并的效果 html代码 <template><div><el-table size"mini" :d…

Python基础知识:整理9 文件的相关操作

1 文件的打开 # open() 函数打开文件 # open(name, mode, encoding) """name: 文件名&#xff08;可以包含文件所在的具体路径&#xff09;mode: 文件打开模式encoding: 可选参数&#xff0c;表示读取文件的编码格式 """ 2 文件的读取 文…

设计模式-规格模式

设计模式专栏 模式介绍模式特点应用场景规格模式和策略模式的区别和联系代码示例Java实现规格模式Python实现规格模式 规格模式在spring中的应用 模式介绍 规格模式&#xff08;Specification Pattern&#xff09;是一种行为设计模式&#xff0c;其目的是将业务规则封装成可重…

【笔记】书生·浦语大模型实战营——第三课(基于 InternLM 和 LangChain 搭建你的知识库)

【参考&#xff1a;tutorial/langchain at main InternLM/tutorial】 【参考&#xff1a;(3)基于 InternLM 和 LangChain 搭建你的知识库_哔哩哔哩_bilibili-【OpenMMLab】】 笔记 基础作业 这里需要等好几分钟才行 bug&#xff1a; 碰到pandas相关报错就卸载重装 输出文字…

【野火i.MX6ULL开发板】开发板连接网络(WiFi)与 SSH 登录、上电自动登录、设置静态IP、板子默认参数

0、前言 参考之前自己写的&#xff1a; http://t.csdnimg.cn/g60P8 参考资料&#xff1a; [野火]《Linux基础与应用开发实战指南——基于i.MX6ULL开发板》_20230323 从野火官网下载 参考博客&#xff1a; http://t.csdnimg.cn/8uh4O 参考官方文档&#xff1a; https://doc.…

【算法每日一练]-练习篇 #Tile Pattern #Swapping Puzzle # socks

目录 今日知识点&#xff1a; 二维前缀和 逆序对 袜子配对(感觉挺难的&#xff0c;又不知道说啥) Tile Pattern Swapping Puzzle socks Tile Pattern 331 题意&#xff1a;有一个10^9*10^9的方格。W表示白色方格&#xff0c;B表示黑色方格。每个(i,j)方的颜色由(i…

PowerDesigner简介以及简单使用

软件简介&#xff1a; PowerDesigner是Sybase公司开发的数据库设计工具&#xff0c;开发人员能搞利用PowerDesigner开发数据流程图、各数据模型如物理数据模型&#xff0c;可以分别从概念数据模型(Conceptual Data Model)和物理数据模型(Physical Data Model)两个层次对数据库…

一点一点,照亮你的美

一、实验要求 当鼠标点击屏幕时&#xff0c;随机出现大大小小的星星闪烁&#xff0c;犹如夜晚的星空 二、实验思路 设置图片的大小 设置事件&#xff08;当鼠标点一下&#xff0c;获取一张图片&#xff09; 设置图片的位置 设置鼠标的位置和图片的相对位置 设置随机大小 …

如何使用GaussDB创建脱敏策略(MASKING POLICY)

目录 一、前言 二、GaussDB中的脱敏策略 1、数据脱敏的定义 2、创建脱敏策略的语法说明 三、在GaussDB中如何创建数据脱敏策略(示例) 1、创建脱敏策略的一般步骤 2、GaussDB数据库中创建脱敏策略的完整示例 1&#xff09;开启安全策略开关&#xff0c;以初识用户omm登录…

这6个设计小白学习网站,海量免费学习教程!

划到最后“阅读原文”——领取工具包&#xff08;超过1000工具&#xff0c;免费素材网站分享和行业报告&#xff09; Hi&#xff0c;我是胡猛夫~&#xff0c;专注于分享各类价值网站、高效工具&#xff01; ​更多资源&#xff0c;更多内容&#xff0c;欢迎交流&#xff01;公…

Unity编辑器扩展(外挂)

每日一句:未来的样子藏在现在的努力里 目录 什么是编译器开发 C#特性[System.Serializable] 特殊目录 命名空间 /*检视器属性控制*/ //添加变量悬浮提示文字 //给数值设定范围&#xff08;最小0&#xff0c;最大150&#xff09; //指定输入框&#xff0c;拥有5行 //默认…

寄快递选哪个平台便宜?快递优惠券免费领取!

寄快递选哪个平台便宜&#xff1f;快递优惠券免费领取&#xff01; 对于市场来说&#xff0c;快递业是非常重要的一部分&#xff0c;它业既贯通市场流通消费投资出口的各环节&#xff0c;又关联一二三各产业。根据相关数据显示&#xff0c;我国的快递行业正呈现势如破竹的劲头&…

双位置继电器DLS-5/2TH 额定电压:110VDC 触点形式:7开3闭 柜内安装

系列型号&#xff1a; DLS-5/1电磁式双位置继电器; DLS-5/2电磁式双位置继电器; DLS-5/3电磁式双位置继电器; DLS-5/2G电磁式双位置继电器; DLS-5/3 220VDC双位置继电器 一、用途 1.1用途 DLS-5双位置继电器(以下简称产品)用于各种保护与自动控制系统中&#xff0c;作为切换…