【C++】STL进阶-- 树形结构的关联式容器(map和multimap)

本文主要内容

1.理解键值对
2.map 的使用
3.multimap 的使用
4.底层结构

1.键值对

键值对是用来表示一对一的数据映射关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表关键字,value代表与key对应的信息值。
我们生活中有许多这样的对应关系,例如英汉互译字典就是典型的模型。每个中文词语与英文单词就存在着一一映射的关系,我们用其他数据结构描述出这样的关系可能需要很多辅助,但是用map就能轻易的进行描述。这就是键值对为我们**在用编程处理一对一数据的时候,提供的快速通道。**下面是键值对的定义:

STL中关于键值对的定义:
//键值对
template
struct pair
{
	typedef K first_type;
	typedef V second_type;

	K first;
	V second;
	pair()
		:first(K())
		, second(V())
	{}

	pair(const K& a, const V&b)
		: first(a)
		, second(b)
	{}
}
make_pair ( , )的定义:
//make_pair 是函数模板,根据pair的类型直接推出参数类型
template
pair make_pair(const K&k, const V&v)
{
	return pair(k, v);
}

2. map的使用

想要深入了解的可以查看:map文档
下面我简单介绍 一下map:

  1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。
  2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的内容。键值 key和值value的类型可能不同,并且在map的内部,key与value通过成员类型value_type绑定在一起, 为其取别名称为pair: typedef pair value_type;
  3. 在内部,map中的元素总是按照键值key进行比较排序的。
  4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序对元素进行 直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。
  5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。
  6. map通常是用红黑树实现的。
map使用示例–英汉词典

map提供一对一的数据处理能力(其中第一个是关键字,第二个是该关键字对应的值),由于这个特性(键值对),我们在描述英汉互译词典时就变得很轻松了。下面是使用map描述字典的示例

示例代码
//map 的使用--英汉互译字典
	void test_map()
	{
		map<string, string> m1;
		map<string, string>m2{ { "apple", "苹果" },
		{ "banan", "香蕉" }, { "orange", "橘子" } };
		cout << m2["apple"] << endl;     //苹果
		cout << m2["peach"] << endl;     //空串
		
		//迭代器使用
		map<string, string>::iterator it = m2.begin();
		//auto it=m2.begin();
		while (it != m2.end())
		{
			cout << (*it).first << ":" << (*it).second << "  ";
			it++;
		}
		cout << endl;
	}

【C++】STL进阶-- 树形结构的关联式容器(map和multimap)_第1张图片

map 的operator[ ]使用示例
  1. 接口介绍:
    mapped_type&operator[ ](const key_type &k )
    功能:直接返回key对应的value值。
    示例:m[k]=2; 如果k的value 不存在就插入,若已经存在则修改。

operator[]的原理是:
构造一个键值对,然后调用insert()函数将该键值对插入到map中
如果key已经存在,插入失败,insert函数返回该key所在位置的迭代器
如果key不存在,插入成功,insert函数返回新插入元素所在位置的迭代器
operator[]函数后 将insert返回值键值对中的value返回

注意: 在元素访问时,有一个与operator[]类似的操作at()函数(该函数不常用),都是通过key找到与key 对应的value然后返回其引用,不同的是:当key不存在时,operator[]用默认的value与key构造键值对然后插入后返回该默认value,at()函数直接抛异常。

示例代码
 void TestMap() {     
	map<string, string> m;      // 构造一个空的map,此时m中一个元素都没有
 	 m ["apple"] = "苹果";     
	cout << m["apple"] << endl;   //返回value值
	cout << m["banan"] << endl;    //插入key
	cout << m.size() << endl;
	m.at("peach");     //直接抛出错误
}

【C++】STL进阶-- 树形结构的关联式容器(map和multimap)_第2张图片

map 中可修改元素的接口使用示例
  1. pair insert(const value_type&x)
    功能:在map中插入键值对x,返回值的键值对:iterator 表示插入位置,bool表明是否插入成功。这里因为能直接返回位置,所以可进行修改。
  2. iterator insert (iterator position,const value_type&x)
    功能:在当前位置插入值为X的键值对,返回该键值对在map中的位置。
  3. iterator find(const key_type &x)
    功能:在map查找key为x的元素,找到就返回该元素位置的迭代器,否则返回end。
  4. size_type size()const
    功能:返回map中有效元素的个数。
  5. size_type erase(const key_type &x)
    功能:删除键值为x的元素。
  6. size_type count(const key_type& x)const
    功能:返回key为x的键值对在map 中的个数,因为map中的key是唯一的,因此返回值只能是1或0。因此可以用它检测key是否存在map中。
示例代码
void TestMap2()
{
	map<string, string> m;
	//用不同的方法再map中插入元素
	m.insert(pair<string, string>("peach", "桃子"));    //用pair直接来构造键值对 
	m.insert(make_pair("banan", "香蕉"));       //用make_pair函数来构造键值对   
	m["apple"] = "苹果";           // 借用operator[]向map中插入元素 
	m.insert(m.find("banan"), make_pair("waterme", "水蜜桃"));  //iterator的insert中的position 只是参考位置
	cout << m.size() << endl;    

	// 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列    
	for (const auto& e : m)       
		cout << e.first << ":" << e.second << endl;    
	cout << endl;      

	// map中的键值对key一定是唯一的,如果key存在将插入失败    
	auto ret = m.insert(make_pair("peach", "桃色"));    
	if (ret.second)        
		cout << "不在map中, 刚插入" << endl;    
	else        
		cout << "key为peach的元素已经存在,如下:" << ret.first->first << ":" << ret.first->second << endl;

	// 删除key为"apple"的元素    
	m.erase("apple");    
	if (m.count("apple"))    //count 检测key在map中的个数,只能是1或0
		cout << "apple还在" << endl;
	else
		cout << "apple被删除" << endl;
	cout << "剩下的水果有 ->" << endl;
	for (auto& e : m)        
	cout << e.first << ":" << e.second << endl;
}

【C++】STL进阶-- 树形结构的关联式容器(map和multimap)_第3张图片

map 小结
  1. map 中的元素是键值对,即一对一的数据处理
  2. map 中的key是唯一的,并且不能修改(value可以变化)
  3. map 中的元素默认按照小于的方式对key进行比较,如果用迭代器去遍历,可以得到一个有序序列(即默认升序)
  4. map 的底层结构是一颗自建的平衡二叉搜索树即红黑树,所以查找效率更高
  5. map 支持[ ]操作符,operator[ ]中实际先进行了查找返回value值,若查找失败就插入(返回value值是默认的)

3. multimap的使用

想要深入了解的伙伴可以查看:multimap文档
下面我就简单介绍一下multimap:

  1. Multimaps是关联式容器,它按照特定的顺序,存储由key和value映射成的键值对,其中 多个键值对之间的key是可以重复的。
  2. 在multimap中,通常按照key排序和惟一地标识元素,而映射的value存储与key关联的内容。key和 value的类型可能不同,通过multimap内部的成员类型value_type组合在一起,value_type是组合key 和value的键值对: typedef pair value_type;
  3. 在内部,multimap中的元素总是通过其内部比较对象,按照指定的特定严格弱排序标准对key进行排序 的。
  4. multimap通过key访问单个元素的速度通常比unordered_multimap容器慢,但是使用迭代器直接遍历 multimap中的元素可以得到关于key有序的序列。
  5. multimap在底层用红黑树来实现的。

multimap中接口使用与map的使用几乎无异。但有以下几点不同处需要注意:

  1. map中的key是唯一的,而multimap中key是可以重复插入的
  2. multimap中的元素也会默认将key按照小于来比较(相同的key值也能输出)
  3. multimap中没有重载operator[]操作(因为key值是可重复的,底层不知道该修改哪个key的value)
示例代码1
void TestMultimap1() 
{
	multimap<string, string> m; //构造一个空的multimap
	m.insert(make_pair("李逵", "黑旋风"));
	m.insert(make_pair("林冲", "豹子头"));
	m.insert(make_pair("鲁达", "花和尚"));
	m.insert(make_pair("李逵", "铁牛")); //尝试插入相同key的不同  
	cout << m.count("李逵") << endl;        // 统计key为李逵的元素有多少个
	for (auto& e : m)    
	cout << "<" << e.first << ":" << e.second << endl; //表示插入成功
}

【C++】STL进阶-- 树形结构的关联式容器(map和multimap)_第4张图片

示例代码2
void TestMultimap2() 
{
	multimap<int, int> m; 
	for (int i = 0; i < 10; ++i)    
		m.insert(pair<int, int>(i, i));
	for (auto& e : m)    
		cout << e.first << ":" << e.second << endl; 
	cout << endl;

	// 返回m中大于等于5的第一个元素 
	auto it = m.lower_bound(5); 
	cout << it->first << ":" << it->second << endl;

	// 返回m中大于5的第一个元素 
	it = m.upper_bound(5); 
	cout << it->first << ":" << it->second << endl; 
} 

【C++】STL进阶-- 树形结构的关联式容器(map和multimap)_第5张图片

底层结构

STL实现有两种不同结构的数据结构:树形结构和哈希结构。

  1. 树形结构的关联式容器主要有四个:map,set,multimap,multiset。这四种容器的共同特点是使用平衡搜索树(即红黑树)作为底层结构,容器中的元素是一个有序的序列。因此红黑树的实现作为重要内容,可参考红黑树的实现原理这篇博客进行理解
  2. 哈希结构的关联式容器主要有两个:unordered_map ,unordered_set。 这两种容器的共同特点是使用哈希列表作为底层结构,容器中的元素是一个无序的序列。因此解决哈希冲突也成为了一个重要内容,可参考哈希冲突解决方法这篇博客进行理解

其他内容

练习:
1.用map 的接口实现< k,v >模型中以key为关键字的排序map 实现对 模型的排序
2.用map 的接口实现< k,v >模型中以value为关键字的排序58同城秋招笔试题解答
扩展:
STL进阶之树形结构的关联式容器—— set和multiset

你可能感兴趣的:(C++,/,数据结构,容器的分类,键值对,树形结构的关联式容器,map,multimap)