详解map容器的使用




map是STL的一个关联容器,它提供一对一 的数据处理能力. 也就是内部存储的有两个部分,一个是固定的键值(从开始插入后就不

会再改变的值)也可以称为关键字另外一个是记录该关键字的状态(大小,翻译,对应关系).所以map的作用很广泛,生活中一一对

的东西太多了,比如你的身份证号和你,比如你需要记录很多不同东西的数量,还有很多很多. 而且map还是有序的.应用场景相

广泛. 但是map也是有不能存储的数据 只要该数据不能够互相比较大小那么就不能使用map存储. 那么为什么呢?

这里是由于map容器底层是使用搜索树来存储数据的,所以你在构建搜索树的时候需要不停的比较大小,这就是原因.而这里使用的搜

索树是较为成熟的红黑树,正因为底层是红黑色所以 map的查找,删 除,插入的 效率都很高. 那么如果你还是不了解为什么,那么你

就需要了解 红黑树的知识了,我有一篇博客专门介绍红黑树原理和实现如果不是很清楚 希望这个可以帮助到你.

我们可以通过map的迭代器改变map的元素内容吗? 如果想要修正元素的键值,答案是不行的,因为Map元素的键值关系到map元素的排

列顺序.任意改变map元素键值将会严重破坏map组织.但如果想要修正元素的实值,答案是可以,因为map元素的实值并不影响map元素的

排列规则,因此,map iterator既不是一种consttant iterator,也不是一种mutable iterato

map拥有与list相同的某些性质: 当客户端对它进行元素新增操作或删除操作时,操作之前的所有迭代器,在操作完成之后都依然有效,当然

那个被删除元素迭代器必然是个例外.



map的成员函数

at
查找具有指定键值的元素。
begin 返回一个迭代器,此迭代器指向映射中的第一个元素。
cbegin 返回一个常量迭代器,此迭代器指向映射中的第一个元素。
cend 返回一个超过末尾常量迭代器。
clear 清除映射的所有元素。
count 返回映射中其键与参数中指定的键匹配的元素数量。
crbegin 返回一个常量迭代器,此迭代器指向反向映射中的第一个元素。
crend 返回一个常量迭代器,此迭代器指向反向映射中最后一个元素之后的位置。
emplace 将就地构造的元素插入到映射。
emplace_hint 将就地构造的元素插入到映射,附带位置提示。
empty 如果映射为空,则返回 true。
end 返回超过末尾迭代器。
equal_range 返回一对迭代器。 此迭代器对中的第一个迭代器指向 map 中其键大于指定键的第一个元素。 此迭代器对中的第二个迭代器指向 map 中其键等于或大于指定键的第一个元素。
erase 从指定位置移除映射中的元素或元素范围。
find 返回一个迭代器,此迭代器指向映射中其键与指定键相等的元素的位置。
get_allocator 返回用于构造映射的 allocator 对象的副本。
insert 将元素或元素范围插入到映射中的指定位置。
key_comp 返回用于对映射中的键进行排序的比较对象副本。
lower_bound 返回一个迭代器,此迭代器指向映射中其键值等于或大于指定键的键值的第一个元素。
max_size 返回映射的最大长度。
rbegin 返回一个迭代器,此迭代器指向反向映射中的第一个元素。
rend 返回一个迭代器,此迭代器指向反向映射中最后一个元素之后的位置。
size 返回映射中的元素数量。
swap 交换两个映射的元素。
upper_bound 返回一个迭代器,此迭代器指向映射中其键值大于指定键的键值的第一个元素。
value_comp 检索用于对映射中的元素值进行排序的比较对象副本。
shrink_to_fit 放弃额外容量。
size 返回vector元素个数
swap 交换两个向量的元素。


访问操作



这里我们需要熟练运用的函数为:at,begin,end,count,find. 


map<int, int> T;

	T[0] = 1;
	T[1] = 2;
	T[2] = 3;
	T[3] = 4;
	//operator[]返回指定下标的引用.

	cout << "map容器中关键值为2的val为:";
	cout << T.at(2) << endl;
	//at函数查找输入键值对应的元素. 

	cout << "从头遍历该map元素" << endl;
	map<int, int>::iterator it = T.begin();
	//返回map中第一个元素位置的迭代器

	while (it != T.end())
	//返回map中最后一个元素下一个位置的迭代器
	{
		cout << it->first << "  ->>>  " << it->second << endl;
		++it;
		//让迭代器跳转到下一个元素的位置.
	}

	cout << "find一个元素的迭代器并且访问它:";
	cout << T.find(3)->first << "  ->>>  " << T.find(3)->second << endl;

运行结果:



插入操作



插入的操作我们我们不是直接就把两个值传给他,我们需要先把两个放进pair里面,比如最基本的插入insert(pair<K,V>(key,val));

这里每次插入的时候都要给pair传入模板类型有点繁琐,所以我想着在这里封装一个函数让模板参数可以自动识别,所以写一个函数为

template<typename K, typename V>
pair<K, V> mymake_pair(const K& key,const V& val)
{
	return pair<K, V>(key, val);
}

其实编译器有一个这个函数,但是我们也需要明白函数的底层构造以及为什么需要这个函数,接下来我们看几种不同的重载的插入:

	map<int, int> T;

	//***1*** 最正常的插入
	T.insert(pair<int, int>(1, 1));
	T.insert(pair<int, int>(2, 2));
	T.insert(pair<int, int>(3, 3));
	//这是最基本的插入操作,这里没有前插后插的,因为搜索树会负责给你安排位置
	//这里不需要你操心.

	T.insert(mymake_pair(4, 4));
	T.insert(mymake_pair(5, 5));
	T.insert(mymake_pair(6, 6));

	map<int, int>::iterator it1 = T.begin();

	cout << "遍历T中的元素:" << endl;
	while (it1 != T.end())
	{
		cout << it1->second << " ";
		cout << "的val为" << " ";
		cout << it1->first << endl;
		++it1;
	}
	cout << endl;

	//***2** 利用迭代器进行区间插入

	std::map<int, int> anothermap;
	anothermap.insert(T.begin(), T.find(4));
	//

	map<int, int>::iterator it2 = anothermap.begin();

	cout << "遍历anothermap中的元素:" << endl;
	while (it2 != anothermap.end())
	{
		cout << it2->second << " ";
		cout << "的val为 " << " ";
		cout << it2->first << endl;
		++it2;
	}

运行结果:





删除操作




其实当你明白插入操作之后,我觉得删除操作,以及删除操作里面的删除迭代器区间的操作你会很容易就Get到. 我这里就直接撸代码了!

	map<int, int> T;

	T.insert(mymake_pair(1, 1));
	T.insert(mymake_pair(2, 2));
	T.insert(mymake_pair(3, 3));
	T.insert(mymake_pair(4, 4));
	T.insert(mymake_pair(5, 5));
	T.insert(mymake_pair(6, 6));

	map<int, int>::iterator it1 = T.begin();

	cout << "遍历T中的元素:" << endl;
	while (it1 != T.end())
	{
		cout << it1->second << " ";
		cout << "的val为" << " ";
		cout << it1->first << endl;
		++it1;
	}
	cout << endl;

	//***2*** 删除单个迭代器

	map<int, int>::iterator it3 = T.find(2);
	//通过find拿到关键字为2的迭代器

	T.erase(it3);
	//然后删除该元素.

	it1 = T.begin();

	cout << "遍历T中的元素:" << endl;
	while (it1 != T.end())
	{
		cout << it1->second << " ";
		cout << "的val为" << " ";
		cout << it1->first << endl;
		++it1;
	}
	cout << endl;


	//***2*** 删除迭代器区间

	it3 = T.find(3);
	//通过find拿到关键字为3的迭代器

	T.erase(it3, T.end());
	//删除掉it3到map容器结束的所有节点.

	it1 = T.begin();

	cout << "遍历T中的元素:" << endl;
	while (it1 != T.end())
	{
		cout << it1->second << " ";
		cout << "的val为" << " ";
		cout << it1->first << endl;
		++it1;
	}
	cout << endl;


	//***3*** 终极大招 删除所有元素.

	T.insert(mymake_pair(1, 1));
	T.insert(mymake_pair(2, 2));
	T.insert(mymake_pair(3, 3));
	T.insert(mymake_pair(4, 4));
	T.insert(mymake_pair(5, 5));
	T.insert(mymake_pair(6, 6));

	T.clear();
	//删除所有元素.

	it1 = T.begin();

	cout << "遍历T中的元素:" << endl;
	while (it1 != T.end())
	{
		cout << it1->second << " ";
		cout << "的val为" << " ";
		cout << it1->first << endl;
		++it1;
	}
	cout << endl;

运行结果:




其他操作


这里map也有和vector和list相似的其他功能,比如size,empty,swap...... 相信大家会用vector,list的功能就会使用map的这些功能.

如果不会使用也没关系! 详细vector的用法 以及 详细的list的用法 这两个博客我写了好久,功能也挺全的,不懂的可以顺便过去

瞧一瞧~   map其实挺好用的,最重要的是尝试自己实现一个Map,这样你的红黑树的理解,你的设计结构能力会有很高的进步.等我实

现ok,会再写一个博客的.



Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐