【C++/STL】map和set介绍

🌈个人主页:秦jh_-CSDN博客
🔥 系列专栏:https://blog.csdn.net/qinjh_/category_12575764.html?spm=1001.2014.3001.5482

 9efbcbc3d25747719da38c01b3fa9b4f.gif​ 

目录

前言

关联式容器 

树形结构的关联式容器 

set 

 set的介绍

构造 

 删除

查找删除

 lower_bound

multiset 

map

map的介绍 

插入

遍历

operator[] 

count

multimap


前言

    💬 hello! 各位铁子们大家好哇。

             今日更新了map和set的相关内容
    🎉 欢迎大家关注🔍点赞👍收藏⭐️留言📝

关联式容器 

vector、list、deque等这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。

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

树形结构的关联式容器 

STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。 

set 

 set的介绍

  •  在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。 set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。
  • set在底层是用二叉搜索树(红黑树)实现的。

注意:

  1. 与map/multimap不同,map/multimap中存储的是真正的键值对,set中只放 value,但在底层实际存放的是由构成的键值对。
  2. set中插入元素时,只需要插入value即可,不需要构造键值对。
  3. set中的元素不可以重复(因此可以使用set进行去重)。
  4. 使用set的迭代器遍历set中的元素,可以得到有序序列

构造 

简单使用:

 set的使用很简单,主要功能是key模型的搜索,次要功能是排序+去重。

set还支持迭代器区间构造和花括号构造。

 删除

 erase参数可以是值,也可以是迭代器。如果传值,如果有该值就删除,没有就没变化。erase还可以迭代器区间删除。

查找删除

 lower_bound

上方是迭代器区间删除的例子。lower_bound就是大于等于,upper_bound就是大于,即左闭右开的区间。 

multiset 

multiset和set的区别就是允许冗余,不去重。 

有多个相同的数时,multiset的find会找中序遍历的第一个 。 

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支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  5. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

value_type就是pair<const Key, T>。

插入

map插入时,类型得是pair。

插入的方式有很多,make_pair相当于函数模板,它会自动识别类型。最后一行是initializer_list的隐式类型转换构造。

遍历

不能直接对迭代器解引用,因为里面有两个值。所以这里的用法跟前面list的模拟很像。

注意上面传引用比较好,这样就不会因为进行深拷贝,而导致效率低下。  


operator[] 

上面的写法太过麻烦,可以使用[]。 如下图:

operator[]的使用相当于下面函数的作用: 

自行翻译一下就变成下面的代码:

里面使用了insert,下面是insert的返回值:

解释一下版本(1)的返回值:

当插入pair后,返回值也是pair。该pair的first指向新插入的节点的迭代器或者已存在节点的迭代器,second为bool值,插入成功返回true,失败返回false。

即:key存在,插入失败,返回pair<存在的key所在节点的迭代器,false>

        key不存在,插入成功,返回pair<新插入的key所在节点的迭代器,true>

了解了operator[]的底层实现,就有了其他用法:

operator[]的本质:给[]一个Key,如果存在,就返回Key对应val的引用。如果不存在,就插入Key,然后val给的是缺省值(string缺省值就是"") 。

count

 

 

count在map中一般用来判断是否存在,在multimap中可以用来数个数。 

multimap

当我们想按数量排序时,因为有相同数量的水果,就需要用multimap。multimap没有重载[],所以只能使用insert。multimap不能重载[],因为已经允许冗余了,如果key有多个,就不知道返回哪个key对应的val。

注意:multimap和map的唯一不同就是:map中的key是唯一的,而multimap中key是可以重复的。 

测试代码

#include<iostream>
#include<set>
#include<map>
#include<vector>

using namespace std;

void test_set1()
{
	//主要功能:key模型搜索
	//次要功能:排序+去重
	set<int> s1;
	s1.insert(1);
	s1.insert(11);
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	s1.insert(2);
	set<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	vector<int> v = { 3,2,8,1,10,2 };
	set<int> s2(v.begin(), v.end());
	for (auto e : s2)
	{
		cout << e << " ";
	}
	cout << endl;

	set<int>s3 = { 3,2,8,1,10,2 };
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;
	s3.erase(8);
	s3.erase(18);
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;

	auto pos = s3.find(10);
	if (pos != s3.end())
	{
		cout << *pos << endl;
		s3.erase(pos);
	}
	else
	{
		cout << "找不到" << endl;
	}
	for (auto e : s3)
	{
		cout << e << " ";
	}
	cout << endl;

}

void test_set2()
{
	set<int> myset;
	for (int i = 1; i < 10; i++) 
		myset.insert(i * 10); // 10 20 30 40 50 60 70 80 90

	for (auto e : myset)
	{
		cout << e << " ";
	}
	cout << endl;
	//[30,70)
	auto itlow = myset.lower_bound(30);         //   >=   
	auto itup = myset.upper_bound(60);          //   >              

	myset.erase(itlow, itup);           // 10 20 70 80 90

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

void test_set3()
{
	//主要功能:key模型搜索
	//次要功能:排序 不去重
	multiset<int> s1;
	s1.insert(1);
	s1.insert(2);
	s1.insert(11);
	s1.insert(3);
	s1.insert(1);
	s1.insert(4);
	s1.insert(2);
	multiset<int>::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	auto pos = s1.find(2);
	while (pos != s1.end()&&*pos==2)
	{
		cout << *pos << " ";
		++pos;
	}
}

void test_map1()
{
	map<string, string> dict;
	pair<string, string> kv1("sort", "排序");
	dict.insert(kv1);
	dict.insert(pair<string, string>("left", "左边"));
	dict.insert(make_pair("right", "右边"));

	// 隐式类型转换
	//单参数和多参数都支持隐式类型转换
	//如果是多参数,用花括号括起来即可
	pair<string, string> kv2 = { "string","字符串" };
	dict.insert({ "string","字符串" });

	map<string, string> dict2 = { {"left", "左边"},{"right", "右边"} };

	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		//cout << *it << " ";  //错误
		cout << (*it).first << ":" << (*it).second << endl;
		cout << it->first << ":" << it->second << endl;
		cout << it.operator->()->first << ":" << it.operator->()->second << endl;

		++it; 
	}
	cout << endl;

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

void test_map2()
{
	string arr[] = { "苹果","西瓜","苹果","西瓜","苹果","苹果","西瓜","苹果","香蕉",
	"苹果","香蕉","苹果","草莓","苹果","草莓" };
	map<string, int> countMap;
	for (auto& e : arr)
	{
		countMap[e]++; 
		/*auto it = countMap.find(e);
		if (it != countMap.end())
		{
			it->second++;
		}
		else
		{
			countMap.insert({ e,1 });
		}*/
	}
	for (auto& kv : countMap)
	{
		cout << kv.first << ":" << kv.second << endl;
	}
	cout << endl;
	 
	multimap<int, string> sortMap;
	for (auto& kv : countMap)
	{
		//sortMap[kv.second] = kv.first;
		sortMap.insert({ kv.second,kv.first });
	}
	cout << endl;

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

void test_map3()
{
	map<string, string> dict;
	dict.insert({ "string","字符串" });

	//插入(一般不这么用)
	dict["right"];

	//插入+修改
	dict["left"] = "左边";
	
	//"查找"
	cout << dict["string"] << endl;

	//修改
	dict["right"] = "右边";

	string str;
	cin >> str;
	if (dict.count(str))
	{
		cout << "在" << endl;
	}
	else
	{
		cout << "不在" << endl;
	}
}

int main()
{
	test_map3();
	return 0;
}

评论 47
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

秦jh_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值