STL之map容器(一般详细)

11 篇文章 3 订阅

作为关联式容器的一种,map 容器存储的都是 pair 对象,也就是用 pair 类模板创建的键值对。其中,各个键值对的键和值可以是任意数据类型,包括 C++ 基本数据类型(int、double 等)、使用结构体或类自定义的类型。

在使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序(不涉及自定义数据类型)。默认情况下,map 容器选用std::less<T>排序规则,如果想更改默认顺序,那又是一波仿函数了。

 另外需要注意的是,使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改。换句话说,map 容器中存储的各个键值对不仅键的值独一无二,键的类型也会用 const 修饰,这意味着只要键值对被存储到 map 容器中,其键的值将不能再做任何修改。

前面提到,map 容器存储的都是 pair 类型的键值对元素,更确切的说,该容器存储的都是 pair<const K, T> 类型(其中 K 和 T 分别表示键和值的数据类型)的键值对元素。

 1.pair键值对

pair<string, int> p("张飞", 27);
pair<string, int> p1 = make_pair("张飞", 28);
cout << p.first << " " << p.second << endl;
cout << p1.first << " " << p1.second << endl;

2.创建map容器

map<std::string, int>myMap;
map<std::string, int>myMap{ {"C语言教程",10},{"STL教程",20} };
map<std::string, int>myMap{make_pair("C语言教程",10),make_pair("STL教程",20)};

map<std::string, int>newMap(myMap)//拷贝构造
map& operator=(const map &mp);//重载赋值构造

 map 类模板还支持取已建 map 容器中指定区域内的键值对,创建并初始化新的 map 容器。

std::map<std::string, int>myMap{ {"C语言教程",10},{"STL教程",20} };
std::map<std::string, int>newMap(++myMap.begin(), myMap.end());

 3.map容器迭代器

STL标准库为 map 容器配备的是双向迭代器(bidirectional iterator)。这意味着,map 容器迭代器只能进行 ++p、p++、--p、p--、*p 操作,并且迭代器之间只能使用 == 或者 != 运算符进行比较

 

 图中 Ei 表示的是 pair 类对象,即键值对。对于 map 容器来说,每个键值对的键的值都必须保证是唯一的。

成员方法功能
begin()返回指向容器中第一个(注意,是已排好序的第一个)键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
end()返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
rbegin()返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
rend() 返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
cbegin()和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
cend() 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
crbegin() 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
crend() 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
find(key)在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
lower_bound(key)返回一个指向当前 map 容器中第一个大于或等于 key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
upper_bound(key) 返回一个指向当前 map 容器中第一个大于 key 的键值对的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
equal_range(key)该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为 key 的键值对(map 容器键值对唯一,因此该范围最多包含一个键值对)。

 equal_range(key) 成员方法可以看做是 lower_bound(key) 和 upper_bound(key) 的结合体,该方法会返回一个 pair 对象,其中的 2 个元素都是迭代器类型,其中 pair.first 实际上就是 lower_bound(key) 的返回值,而 pair.second 则等同于 upper_bound(key) 的返回值。

pair <map<string, string>::iterator, map<string, string>::iterator> myPair = myMap.equal_range("C");

后三项在map里边用的不多,因为map容器,其返回的范围内最多也只有 1 个键值对

3.获取map键对应的值

第一种方法:map 类模板中对[ ]运算符进行了重载,这意味着,类似于借助数组下标可以直接访问数组中元素,通过指定的键,我们可以轻松获取 map 容器中该键对应的值。 

 [ ] 运算符确实有“为 map 容器添加新键值对”的功能,但前提是要保证新添加键值对的键和当前 map 容器中已存储的键值对的键都不一样。往map容器里边添加键值对的方法:

//第一种插入方式
m.insert(pair<int, int>(1, 10));
//第二种插入方式
m.insert(make_pair(2, 20));
//第三种插入方式
m.insert(map<int, int>::value_type(3, 30));
//第四种插入方式
m[4] = 40; 

第二种方法:除了借助 [ ] 运算符获取 map 容器中指定键对应的值,还可以使用 at() 成员方法。和前一种方法相比,at() 成员方法也需要根据指定的键,才能从容器中找到该键对应的值;不同之处在于,如果在当前容器中查找失败,该方法不会向容器中添加新的键值对,而是直接抛出 out_of_range 异常

与find不同,at返回的直接就是键所对应的值,而find返回的是迭代器

4. map容器插入键值对insert()

 无需指定插入位置,直接将键值对添加到 map 容器中。

可以判断键值对是否插入

  • 对于插入成功的 insert() 方法,其返回的 pair 对象中包含一个指向新插入键值对的迭代器和值为 1 的 bool 变量
  • 对于插入失败的 insert() 方法,同样会返回一个 pair 对象,其中包含一个指向 map 容器中键为 "重复" 的键值对和值为 0 的 bool 变量。
ret = mymap.insert({ 1001,"张" });
cout << << ret.first->first << ", " << ret.first->second << ret.second  << endl;
//ret.first是一个迭代器,可以用指针的当时,也可以写(*ret.first).first

insert() 方法还支持向当前 map 容器中插入其它 map 容器指定区域内的所有键值对

5.成员函数

empty() 若容器为空,则返回 true;否则 false。
size()返回当前 map 容器中存有键值对的个数。
max_size()返回 map 容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。
operator[]map容器重载了 [] 运算符,只要知道 map 容器中某个键值对的键的值,就可以向获取数组中元素那样,通过键直接获取对应的值。
at(key)找到 map 容器中 key 键对应的值,如果找不到,该函数会引发 out_of_range 异常。
insert()向 map 容器中插入键值对。
erase()删除 map 容器指定位置、指定键(key)值或者指定区域内的键值对。后续章节还会对该方法做重点讲解。
swap()交换 2 个 map 容器中存储的键值对,这意味着,操作的 2 个键值对的类型必须相同。
clear()清空 map 容器中所有的键值对,即使 map 容器的 size() 为 0。
emplace()在当前 map 容器中的指定位置处构造新键值对。其效果和插入键值对一样,但效率更高。
emplace_hint()在本质上和 emplace() 在 map 容器中构造新键值对的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示键值对生成位置的迭代器,并作为该方法的第一个参数。
count(key)在当前 map 容器中,查找键为 key 的键值对的个数并返回。注意,由于 map 容器中各键值对的键的值是唯一的,因此该函数的返回值最大为 1。

 给了一个算例用到了vector容器和multimap

#include<iostream>
#include<string>
#include<vector>
#include<map>
#include <ctime>
using namespace std;

//公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作
//* 员工信息有: 姓名  工资组成;部门分为:策划、美术、研发
//* 随机给10名员工分配部门和工资
//* 通过multimap进行信息的插入  key(部门编号) value(员工)
//* 分部门显示员工信息

//1. 创建10名员工,放到vector中
//2. 遍历vector容器,取出每个员工,进行随机分组
//3. 分组后,将员工部门编号作为key,具体为value,放入到multimap容器中
//4. 分部门显示员工信息



class Person
{	
public:
	Person()
	{
		this->c_name = " ";
		this->c_salay = 0;
	}
	string c_name;
	int c_salay;
};


template<class T>
void Print(const T & my)
{
	for (T::const_iterator it=my.begin();it!=my.end();it++)
	{
		cout << (*it) << " ";
	}
	cout << endl;
}
template<> void Print(const vector<Person>& my)
{
	for (vector<Person>::const_iterator it = my.begin(); it != my.end(); it++)
	{
		cout << (*it).c_name << " " << (*it).c_salay<< endl;;
	}
	cout << endl;
}

template<> void Print(const multimap<int, Person>& m)
{
	for (int j = 1; j != 4; j++)
	{
		multimap<int, Person>::const_iterator result = m.find(j);
		int num = m.count(j);
		switch (j)
		{
		case 1:	cout << "所属部分:" << "策划部" << endl; break;
		case 2:	cout << "所属部分:" << "宣传部" << endl; break;
		case 3:	cout << "所属部分:" << "研发部" << endl; break;
		default:
			break;
		}
		
		for (int index = 0; result != m.end() && index != num; result++, index++)
		{
			cout << "姓名:" << result->second.c_name << "      " << "薪资:" << result->second.c_salay << endl;
		}
		cout << "----------------------------------------------------------------" << endl;
	}
	
}

void CreatVector(vector<Person>& v)
{
	string str = "ABCDEFGHIJ";
	srand(time(NULL)); /*根据当前时间设置“随机数种子”*/
	for (int i=0; i<10; i++)
	{
		Person p;
		string name = "员工";
		name += str[i];
		int salary = rand() % 10000 + 10000;//产生10000~19999的随机数;
		p.c_name = name; p.c_salay = salary;
		v.push_back(p);
	}


}
void CreatMultimap(multimap<int, Person>& m,const vector<Person>& v)
{
	srand(time(NULL)); /*根据当前时间设置“随机数种子”*/
	for (vector<Person>::const_iterator it = v.cbegin(); it != v.cend(); it++)
	{
		int index = rand() % 3 + 1;//1策划、2美术、3研发
		m.insert(make_pair(index, (*it)));
	}
}


void test()
{
	vector<Person> v;
	CreatVector(v);
	multimap<int, Person> m;
	CreatMultimap(m,v);
	Print(m);
}

int main()
{
	test();
	return 0;
	system("pause");
}

 

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值