6-6-2:STL之map和set——map的基本使用

Posted 快乐江湖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6-6-2:STL之map和set——map的基本使用相关的知识,希望对你有一定的参考价值。

(1)基本介绍

  1. map按照特定的次序(依据key来比较来存储由键key和值value所组合而成的元素,这种元素称为pairttypedef pair<const key,T value> value_type
    在这里插入图片描述

  2. map中的key用于唯一的标识元素和排序value存储的则是与key对应或关联的内容。keyvalue的类型可以不同。

  3. map中通过键值访问单个元素的速度通常要比unordered_map慢,但是map允许根据顺序队元素进行直接迭代

  4. map支持下标访问,也就是[]运算符,如果在[]中放入key,返回的结果就是与key对应的value

  5. map实现为平衡搜索树(红黑树)

(2)键值对

键值对本质也是一种结构,用来表示数据与数据之间一一对应的关系,该结构中一般只包含两个成员变量key和value,key为键,value为键所对应的值。生活中常见的英文单词和中文含义(大多数情况)就是典型的键值对。

STL中(SGI版本)关于键值对的定义如下

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)
 {}
};

(3)map的使用

使用map时需要引入头文件

#include <map>

A:map的模板参数列表

template<
	class key;//键值对中key的类型
	class T;//键值对中value的类型
	class compare=less<key>;//仿函数,一般依据key,按照小于来比较
	class alloc=allocator<pair<const key,T>>;//空间配置器


>

B:map的常用接口

函数声明接口作用
bool empty() const判断map是否为空
size_type size() const返回set中有效元素的个数
mapped_type& operator[](const key_type& k)返回key对应的value
pair<iterator,bool> insert(const value type& x)在map中插入键值对<key,value>
void erase(iterator position)删除某位置元素
size_type erase(const key_type& x)删除键为x的元素
void erase(iterator first,iterator last)删除迭代器区间内的元素
void clear()将map清空
void swap(set<k,t,c,a>& st)交换两个map
iterator find(const key_type& x)const返回map中key为x的元素的位置
sizet_type count(const key_type& x) const返回map中key为x的个数,由于key是唯一的,因此其返回值要么是0,要么是1,可以用于判断一个key是否在map当中

C:map使用举例

1:构造一个空的map,然后不断insert,由于插入的元素是一个类,所以可以使用匿名对象;然后访问键值对,使用迭代器访问时,访问的是一个结构体,其中结构体的第一个元素first代表key,第二个元素second代表value

void test3()
{
	map<string, string> m;
	m.insert(pair<string, string>("melon", "西瓜"));
	m.insert(pair<string, string>("pitaya", "火龙果"));
	m.insert(pair<string, string>("grapefruit", "柚子"));
	m.insert(pair<string, string>("Cherry", "樱桃"));

	map<string, string>::iterator it = m.begin();
	while (it != m.end())
	{
		cout << "英文中" << it->first << "对应的中文意思是:" << it->second << endl;
		it++;
	}

	cout << "===========================================================================" << endl;
	for (auto& e : m)
	{
		cout << "英文中" << e.first << "对应的中文意思是:" << e.second << endl;
	}

}

在这里插入图片描述

  • 需要注意的是除了可以使用pair<string,string>("melon","西瓜")也就是匿名对象传参时,也可以使用make_pair("melon","西瓜"),这样写更加方便。

2:有一个string数组,里面含有多个string,每个string表示一种水果,其中有些string是重复的,统计出有多少种水果,并且每个水果各有多少个

void test4()
{
	string fruits[] = { "苹果","樱桃","苹果","香蕉","苹果","樱桃","梨儿","火龙果","香蕉" };
	map<string, int> each_fruit_number;
	for (auto& e : fruits)
	{
		auto ret = each_fruit_number.find(e);//先找是否在map中存在过,也就是是否存在键为e的键值对
		if (ret != each_fruit_number.end())//说明存在
		{
			ret->second++;//相应水果数目增加
		}
		else
		{
			each_fruit_number.insert(make_pair(e, 1));//如果不存在就增加一种水果,初始数量为1
		}
	}

	cout << "一共有" << each_fruit_number.size() << "种水果" << endl;
	for (auto& e : each_fruit_number)
	{
		cout << e.first << "共有:" << e.second << "个" << endl;
	}

}

在这里插入图片描述

(4)operator []详解

其实上面统计水果出现次数的例子的代码可以用opeartor []直接代替

void test5()
{
	string fruits[] = { "苹果","樱桃","苹果","香蕉","苹果","樱桃","梨儿","火龙果","香蕉" };

	map<string, int> each_fruit_number;

	for (auto& f : fruits)
	{
		each_fruit_number[f]++;
	}

	for (auto& e : each_fruit_number)
	{
		cout << e.first << "共有:" << e.second << "个" << endl;
	}

}

在这里插入图片描述
那么operator []为什么可以直接统计呢,这和其实现的逻辑有关。
官方文档对于这个重载是这样解释的:

mapped_type& operator[](const key_type& k);
  • 其中mapped_type实际就是第二个模板参数T
  • 其中key_type实际是第一个模板参数key

如果形参中传过来的k匹配到了元素,即key,那么就返回key对应的T的值
如果形参中传过来的k一个key都没有匹配到,那么就会插入一个新的元素(值为k)然后返回其对应T的引用。

然后map::at这个成员函数的,在元素存在时和[]具有相同的效果,但是如果不存在直接会抛出异常

同理根据上面的描述,也可以写出另外一种统计次数的写法

insert会返回一个pair,其中pair中的第一个元素first是一个迭代器,它要么会指向那个新插入的元素要么会指向(插入失败)与插入元素相等的元素。第二个元素如果为true表示元素被成功插入,如果为false表示要插入的元素已经存在了。

void test6()
{
	string fruits[] = { "苹果","樱桃","苹果","香蕉","苹果","樱桃","梨儿","火龙果","香蕉" };

	map<string, int> each_fruit_number;

	for (auto& f : fruits)
	{
		pair<map<string, int>::iterator, bool> ret = each_fruit_number.insert(make_pair(f, 1));
		if (ret.second == false)//插入失败,表示f已经存在
		{
			ret.second++;
		}
	}

	for (auto& e : each_fruit_number)
	{
		cout << e.first << "共有:" << e.second << "个" << endl;
	}

}

在这里插入图片描述
其中,[]函数的的返回值为

(*((this->insert(make_pair(k,mapped_type()))).first)).second

分解如下
在这里插入图片描述

也就是该函数内的逻辑实际上是下面这样的

Value& operator[](const K& k)
{
	pair<iterator,bool> ret=this->insert(k,V());
	return ret.first->second;
}

因此,map中的[]主要有两层作用

  1. 如果k不存在,插入pair(k,v),然后返回v的引用
  2. 如果k存在,不插入,返回与k相等的那个结点的v的引用

所以[]可以用来插入,也可以用于修改(因为他返回的是引用)
在这里插入图片描述

以上是关于6-6-2:STL之map和set——map的基本使用的主要内容,如果未能解决你的问题,请参考以下文章

6-6:STL之map和set

C++STL之map和set的使用

C++STL之map和set的使用

带你深入理解STL之Set和Map

C++从青铜到王者第二十篇:STL之setmapmultisetmultimap的初识

Set和Map的内部结构