(C++ 进阶)map & set

目录

一  关联式容器(KV模型)

二 键值对

三 树形结构的关联式容器

1  set

1.1 set的基本概念与注意事项

1.2  set的遍历

1.3 set 的查找与删除

2 multiset

3 map

3.1 概念

3.2 map的迭代器遍历方式

3.3 简化嵌套结构

3.4 统计水果出现次数

3.5 [ ]的重载使用

3.6 topK问题

4 multimap


一  关联式容器(KV模型)

用关联式容器 来存储数据,与序列式容器不同的是,其 里面存储的是 <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)
 {}

};

三 树形结构的关联式容器

为了满足不同的使用场景, STL 总共实现了两种不同结构的管理式容器: 树型结构与哈希结构 树型结构的关联式 容器主要有四种: map、set、multimap、multiset 。这四种容器的共同点是:使用平衡搜索树 ( 即红黑树 ) 作为其底层结构,容器中的元素是一个有序的序列。

1  set

1.1 set的基本概念与注意事项

①  set 是按照一定次序存储元素的容器
②   set 中,元素的 value 也标识它 (value 就是 key ,类型为 T) ,并且每个 value 必须是唯一的。 set 中的元素不能在容器中修改( 元素总是 const) ,但是可以从容器中插入或删除它们。
③   在内部, set 中的元素总是按照其内部比较对象 ( 类型比较 ) 所指示的特定严格弱排序准则进行排序。
④  set 容器通过 key 访问单个元素的速度通常比 unordered_set 容器慢,但它们允许根据顺序对子集进行直接迭代。
  set 在底层是用二叉搜索树 ( 红黑树 ) 实现的。
注意:
①   map/multimap 不同, map/multimap 中存储的是真正的键值对 <key, value> set中只放value,但在底层实际存放的是由<value, value>构成的键值对。
  set 中插入元素时,只需要插入 value 即可,不需要构造键值对。
  set 中的元素不可以重复 ( 因此可以使用 set 进行去重 )
   使用 set 的迭代器遍历 set 中的元素,可以得到有序序列
⑤  set 中的元素默认按照小于来比较
  set 中查找某个元素,时间复杂度为:O(log2N)
  set 中的元素不允许修改,因为Value就是它的键,随意修改会破坏树的结构。
⑧  set 中的底层使用二叉搜索树 ( 红黑树 ) 来实现。

1.2  set的遍历

	set<int> s;
	s.insert(10);
	s.insert(1);
	s.insert(99);
	s.insert(101);
	s.insert(50);
	s.insert(10);
	s.insert(6);
	s.insert(55);
	s.insert(10);

	//遍历方式一 迭代器
	//排序加去重
	set<int>::iterator it = s.begin();
	while (it != s.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
	//降序
	set<int>::reverse_iterator it1 = s.rbegin();
	while (it1 != s.rend())
	{
		cout << *it1 << " ";
		it1++;
	}
	cout << endl;
	//遍历方法二 范围for(基于迭代器)
	for (auto e : s)
	{
		cout << e << " ";
	}
	cout << endl;

1.3 set 的查找与删除

	//查找
	set<string> sstr;
	sstr.insert("sort");
	sstr.insert("add");
	sstr.insert("sum");
	sstr.insert("adjust");
	sstr.insert("list");
	set<string>::iterator iter = sstr.find("list");
	if (iter != sstr.end())
	{
		cout << "找到了" << *iter << endl;
	}
	else
	{
		cout << "没找到" << endl;
	}

	//因为set底层为搜索二叉树KEY模型,所以不支持随便更改数据的值,否则可能会破坏结构
	//删除
	auto pos = sstr.find("sort");
	sstr.erase(pos);
	sstr.erase("list");

2 multiset

 与set的区别是,multiset中的元素可以重复,set是中value是唯一的。

3 map

3.1 概念

①  map 是关联容器,它按照特定的次序 ( 按照 key 来比较 ) 存储由键值 key 和值 value 组合而成的元素。
②   map 中, 键值key通常用于排序和惟一地标识元素 而值 value 中存储与此键值 key 关联的内容。键值key和值 value 的类型可能不同,并且在 map 的内部, key value 通过成员类型 value_type 绑定在一起,为其取别名称为pair: typedef pair value_type;
③   在内部, map 中的元素总是按照键值 key 进行比较排序的。
④  map 中通过键值访问单个元素的速度通常比 unordered_map 容器慢,但 map 允许根据顺序对元素进行直接迭代( 即对 map 中的元素进行迭代时,可以得到一个有序的序列 )
⑤  map支持下标访问符,即在[]中放入key,就可以找到与key对应的value
⑥  map 通常被实现为二叉搜索树 ( 更准确的说:平衡二叉搜索树 ( 红黑树 ))

3.2 map的迭代器遍历方式

//map的基本使用
void map_test(void)
{
	map<int, double> m;
	//调用pair的构造函数,构造一个匿名对象插入
	m.insert(pair<int, double>(1, 8.9));
	m.insert(pair<int, double>(5, 45.4));
	m.insert(pair<int, double>(7, 9.0));
	m.insert(pair<int, double>(2, 8.9));
	m.insert(pair<int, double>(3, 7.8));
	m.insert(pair<int, double>(7, 6.9));//插入不成功,键值相同
	//调用函数模板构造对象。
	//好处:不需要去声明pair的参数,让函数自己推演,用起来方便
	m.insert(make_pair(7, 6.9));

	//迭代器遍历
	map<int, double>::iterator it = m.begin();
	while (it != m.end())
	{
		//cout << (*it).first << ":" << (*it).second << "  ";
		cout << it->first << ":" << it->second << "  ";
		it++;
	}
	cout << endl;
}

3.3 简化嵌套结构

//简化嵌套结构
void map_test1(void)
{
	typedef std::map<std::string, std::string> DICT;
	typedef std::pair<std::string, std::string> DICT_KV;
	typedef std::map<std::string, std::string>::iterator DICT_IT;

	//std::map<std::string,std::string> dic;
	DICT dic;

	//dic.insert(std::pair<std::string, std::string>("insert", "插入"));
	//dic.insert(std::pair<std::string, std::string>("sort", "排序"));
	//dic.insert(std::pair<std::string, std::string>("find", "查找"));
	dic.insert(DICT_KV("insert", "插入"));
	dic.insert(DICT_KV("sort", "排序"));
	dic.insert(DICT_KV("find", "查找"));
	dic.insert(DICT_KV("left", "左边"));

	DICT_IT dit = dic.begin();
	while (dit != dic.end())
	{
		//key值不可修改,但是value可以修改
		dit->second.insert(0, "{");
		dit->second += "}";

		cout << dit->first << "--" << dit->second << endl;
		dit++;
	}

	auto ret = dic.find("left");
	if(ret != dic.end())
	{
		//可读性优化
		string& str = ret->second;
		str.insert(str.size() - 1, "、剩余");
	}

	cout << endl;
	dit = dic.begin();
	while (dit != dic.end())
	{
		cout << dit->first << "--" << dit->second << endl;
		dit++;
	}

}

3.4 统计水果出现次数

//统计水果出现次数
void map_test2(void)
{
	思路一
	//string arr[] = { "苹果","苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "香蕉", "苹果", "苹果" };
	//std::map<std::string, int> countMap;
	//for (const auto& str : arr)
	//{
	//	std::map<std::string, int>::iterator it = countMap.find(str);
	//	//找到了就不是第一次出现,数量加加
	//	if (it != countMap.end())
	//	{
	//		it->second++;
	//	}
	//	//没找到,第一次出现,插入
	//	else
	//	{
	//		countMap.insert(make_pair(str,1));
	//	}
	//}
	//for (const auto& e : countMap)
	//{
	//	cout << e.first << "--" << e.second << endl;
	//}

	思路二
	//string arr[] = { "苹果","苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
	//std::map<std::string, int> countMap;
	//for (const auto& str : arr)
	//{
	//	auto ret = countMap.insert(make_pair(str, 1));
	//	if(ret.second==false)
	//	{
	//		ret.first->second++;
	//	}
	//}
	//for (const auto& e : countMap)
	//{
	//	cout << e.first << "--" << e.second << endl;
	//}
	
	//思路三
	string arr[] = { "苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
	map<string, int> countMap;
	for (const auto& str : arr)
	{
			countMap[str]++;
	}
	for (const auto& e : countMap)
	{
		cout << e.first << "--" << e.second << endl;
	}
}

3.5 [ ]的重载使用

//[key],key为结点键值,[key]会返回结点的value的引用
void map_test3(void)
{
	map<string,string> sortmap;
	sortmap.insert(make_pair("left", "左边"));
	cout << sortmap["left"] << endl;

	//插入right,value为右边。
	sortmap["right"] = "右边";
	//插入sort,value为缺省值
	sortmap["sort"];
	sortmap["insert"] = "插入";

	sortmap["left"] += "、剩余";
	cout << sortmap["left"] << endl;

}

3.6 topK问题

//TOPK问题
struct MapItCompare
{
	bool operator()(map<string, int>::iterator x, map<string, int>::iterator y)
	{
		return x->second > y->second;
	}
};
void map_test4(void)
{
	string arr[] = { "苹果", "香蕉","西瓜", "苹果", "香蕉", "香蕉", "苹果", "苹果" };
	map<string, int> countMap;
	for (const auto& str : arr)
	{
		countMap[str]++;
	}
	//for (const auto& e : countMap)
	//{
	//	cout << e.first << "--" << e.second << endl;
	//}

	//排序一
	vector<map<string, int>::iterator> v1;
	map<string, int>::iterator countMapIt = countMap.begin();
	while (countMapIt != countMap.end())
	{
		v1.push_back(countMapIt);
		countMapIt++;
	}
	sort(v1.begin(),v1.end(),MapItCompare());

	//排序二
	//map<int, string,greater<int>> sortMap;//降序
	map<int, string> sortMap;//升序
	for (auto e : countMap)
	{
		sortMap.insert(make_pair(e.second, e.first));
	}
	for (auto e : sortMap)
	{
		cout << e.second << "--" << e.first << endl;
	}
}

4 multimap

multimap和map的区别:①map中的key是唯一的,而multimap中key是可以重复的。
                                          ②multimap中没有重载operator[]操作,因为键值可以重复
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C++中的容器有很多种,其中包括mapsetmap是一种关联容器,它存储了一组键值对,每个键对应一个值。map中的键是唯一的,且按照某种顺序进行排序。set也是一种关联容器,它存储了一组唯一的值,并按照一定的顺序进行排序。mapset都可以通过迭代器进行遍历和访问。引用、和中的代码示例展示了如何使用mapset进行操作和排序。 在示例代码中,map的键是字符串类型,值是整数类型。可以使用insert函数向map中插入键值对,使用[]运算符访问和修改特定键对应的值。set中只存储了值,可以使用insert函数插入值,使用find函数查找特定的值。 需要注意的是,mapset中的元素是按照键的顺序进行排序的,因此在示例代码中使用了不同的排序方式。map默认是按照键的升序进行排序的,可以使用greater<int>作为模板参数,将其改为按值的降序进行排序。 总结起来,C++中的mapset是用来存储一组唯一的键值或值的容器,可以通过迭代器进行遍历和访问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++进阶mapset](https://blog.csdn.net/qq_52433890/article/details/124850598)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zhang丶&|!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值