C++ set 和 map学习

一、set(multiset)的基本知识和使用

 set也是一种我们直接可以使用的容器,使用应该包含 #include <set> 这个头文件。此处暂且不讨论其底层,只探讨set如何使用即可。

我们看到,set 的模板参数有三个,第一个就是其存储的数据类型,第二个是仿函数,决定到时候排序的逻辑,第三个是空间配置器,我们在使用中着重写第一个,而后两个我们目前的学习程度几乎用不到。

1. set的构造

我们可以看到,set的构造基本上和我们学的vector,list等容器的构造类似,因为set也是支持迭代器的,所以也是很简单的。

2. set的增删查

我们来看看下面的代码:

int main()
{
	set<int> s1;

	//set的插入
	s1.insert(4);
	s1.insert(1);
	s1.insert(9);
	s1.insert(5);
	
	for (auto a : s1)
	{
		cout << a << " ";
	}
	cout << endl;

	auto found1 = s1.find(10);//找不到即返回end()

	if (found1 == s1.end())
		cout << "找不到" << endl;
	auto found2 = s1.find(5);

	s1.erase(found2);//支持迭代器删除

	s1.erase(4);//支持直接删除内容
	//注意,删除同样会导致迭代器失效

	for (auto a : s1)
	{
		cout << a << " ";
	}
	cout << endl;
 	return 0;
}

运行结果:

set在插入过程中,底层已经按照升序,将插入的内容排号顺序了,我们在删除的过程中,set仍然保持着升序。需要注意的是,当我们使用find功能时,如果没有查找到,则会返回set的end()迭代器。同样的,erase也支持迭代器区间删除,如果执行 erase(s1.begin(),s1.end()); 那么我们将删除set中所有的元素。

multiset和set的使用基本完全类似,因为set是不能接受相同的值的,也就是说我们如果插入了一个set中已经存在的值,那么我们会插入失败,而multiset不会插入失败,因为multiset支持值冗余。结果就是二者均会默认升序,而set会去重,multiset不会。

再是multiset中的find和erase功能,其中由于multiset会存在多个值,因此find返回的是其 中序第一个值得迭代器。而erase删除时,如果该值存在多个,erase会将其全部删除。

二、map的基本知识和使用

 这是map的声明,Key就是map底层关键字的类型,而T是map底层value的类型,同理set,一般情况下我们不需要传入后两个模板参数,只需要传入Key 和 T 即可。

1.pair类型

map的底层数据存储,是用pair<Key,T>来存储键值对数据。

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)
	{}
	template<class U, class V>
	pair(const pair<U, V>& pr) 
		: first(pr.first)
		, second(pr.second)
	{}
};

这就是pair的简单实现,我们从上面就可以看出来,pair内可以存储两个分别为T1 和 T2 类型的数据,而map的插入或者构造是需要pair的。

2. map的构造

还是一样,构造和前面没什么太大的区别,我们直接来看map的增删查改。

3.map的增删查

int main()
{
	map<string, string> m1;
	pair<string, string> p1("地图", "map");
	m1.insert(p1);
	m1.insert(pair<string, string>("你好", "hello"));
	m1.insert({ "自动的","auto" });

	for (auto a : m1)
	{
		cout << a.first << "->" << a.second << endl;
	}
	return 0;
}

 运行结果:

map在插入过程中,会按照Key的大小进行自动排序,因此map一定程度上也可以帮助我们实现排序有关功能。

m1.erase("你好");
auto found = m1.find("地图");
cout << found->first << "->" << found->second << endl;
cout << endl;
for (auto a : m1)
{
	cout << a.first << "->" << a.second << endl;
}

运行结果如下:

也就是说,map的增删查和set基本一致,要注意的是map的插入是一个pair的类型,而删除和查找,只对map的Key有效,我们不能使用map的value来进行删除和查找。

4. map的[]功能样例

我们来看下面的代码:

int main()
{
	map<string, int> countMap;
	string arr[] = { "苹果","香蕉", "凤梨", "苹果", "猕猴桃", "香蕉", "苹果" };

	for (const auto& str : arr)
	{
		countMap[str]++;
	}

	for (const auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	//修改凤梨的个数
	countMap["凤梨"] = 20;

	cout << endl;

	for (const auto& e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
	return 0;
}

运行结果如下:

这是我们一个统计水果个数的简单代码,通过map来实现,我们在下面也通过了[]来实现了修改map中Key值对应的value的数据,那么map中的[]该如何理解呢?

其实本质很简单,[]是运算符重载,如果map中没有[]中的Key值,例如上方在[]中写的str,那么我们就会插入该Key值,对应的value值是value所对类型的默认值,然后我们可以对该Key所对的value进行修改例如上方的++。如果Key已经存在,那么我们就只能对齐value进行修改,例如上方对凤梨个数的修改。

此时map中没有西瓜这个水果,也就是没有西瓜这个Key,那么我们只进行countMap["西瓜"];操作,会发生什么呢?完全正确,map会插入西瓜作为Key而其对应的value类型为int,其默认值为0,所以到时我们打印出来的就是 西瓜:0

以上内容如有错误,欢迎批评指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值