大话STL第六期——map/multimap

书接上期我们讲到set容器,这一期我们聊聊同为关联容器的单映射容器map/多映射容器multimap,在实际开发中也经常使用

大话STL第六期——map/multimap_第1张图片

文章目录

什么是map?

map和multimap区别

map的API

1.map的构造和赋值

2.map交换和大小

3.map的几种初始化

4.map的插入和删除

5.map查找和统计

6.同set一般map的自定义排序(也可以自定义函数写或者仿函数)

map容器的原型,默认的第三个参数其实是less,从小到大

map使用案例:


什么是map?

首先要明白映射类似于函数的对应关系,每个x对应一个y,而map是每个键对应一个值。上期我们讲到pair对组可转入观看,大话STL第五期——set/multiset(含pair对组)

map 容器存储的都是 pair 对象,也就是用 pair 类模板创建的键值对。其中,各个键值对的键和值可以是任意数据类型,pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)

  • map同set一样所有元素都会根据元素的键值自动排序(默认从小到大)
  • 优点:可以根据key值快速找到value值
  • 底层数据结构为红黑树
  • 另外需要注意的是,使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改
  • 同样的与set和multiset类似,map/multimap的唯一区别就是map不允许有重复键值出现,而multimap允许
  • map 容器配备的是双向迭代器(bidirectional iterator)。这意味着,map 容器迭代器只能进行 ++p、p++、--p、p--、*p 操作,并且迭代器之间只能使用 == 或者 != 运算符进行比较。
     

map和multimap区别

指的是 multimap 容器具有和 map 相同的特性,即 multimap 容器也用于存储 pair 类型的键值对(其中 K 表示键的类型,T 表示值的类型),其中各个键值对的键的值不能做修改;并且,该容器也会自行根据键的大小对存储的所有键值对做排序操作。和 map 容器的区别在于,multimap 容器中可以同时存储多(≥2)个键相同的键值对。

和 map 容器相比,multimap 未提供 at() 成员方法,也没有重载 [] 运算符。这意味着,map 容器中通过指定键获取指定指定键值对的方式,将不再适用于 multimap 容器。其实这很好理解,因为 multimap 容器中指定的键可能对应多个键值对,而不再是 1 个。

map可以
map[xx]++;
map[xx]=xxx..;

multimap不可以这样
int main()
{
	mapmp = { {2,10},{1,50},{3,8,} ,{3,15} };//按前后顺序 只能插入到3,8
	mp.insert(pair(3, 10)); //插不进去
	Show(mp);

	multimapmp1 = { {2,10},{1,50},{3,8},{3,11} };//用初始化列表也可以写键值相同的
	mp1.insert(pair(3, 10));//可以插进去
	Show1(mp1);
	return 0;

}

大话STL第六期——map/multimap_第2张图片

map的API

1.map的构造和赋值

map mp; //map没骗人构造函数
map(const map &mp);//拷贝构造
map& operator=(const map &mp);//重载等号操作符
void Show(map& st)
{
	for (auto it = st.begin(); it != st.end(); ++it)
	{
		cout <<(*it).first<<" "<< it->second<<" " << endl;
	}
	cout << "------------------" << endl;
}

int main()
{
	mapmp;
	mp.insert(pair(2, 10));
	mp.insert(pair(1, 20));
	mp.insert(pair(3, 20));
	mp.insert(pair(1, 30));//不允许有重复key值,最后一个pair不会插进去
	Show(mp);
	//拷贝构造
	mapmp1(mp);
	Show(mp1);
	//赋值
	mapmp2;
	mp2 = mp1;
	Show(mp2);
	
	return 0;

}

2.map交换和大小

size();//返回容器中元素数目
empty();//判断容器是否为空
swap();//交换两个容器
void Show(map& st)
{
	for (auto it = st.begin(); it != st.end(); ++it)
	{
		cout <<(*it).first<<" "<< it->second<<" " << endl;
	}
	cout << "------------------" << endl;
}

int main()
{    
	//建议
	mapmp = { {2,10},{1,50},{3,8}};//利用初始化列表初始化
	Show(mp);
	if (mp.empty())
	{
		cout << "为空" << endl;
	}
	else
		cout << "不空" << endl;
	cout << "容器元素个数: " << mp.size() << endl;
	
	//交换
	mapmp1{ {1,1},{2,5},{5,10} };
	mp.swap(mp1);
	Show(mp);
	Show(mp1);

	return 0;
}

3.map的几种初始化

我们可以将它map结点理解为三部分:

大话STL第六期——map/multimap_第3张图片

理解为四部分,通过键值对进行插入,系统调用对象的运算符[]重载函数,运算符=重载函数实现: 

大话STL第六期——map/multimap_第4张图片

void Show(map& st)
{
	for (auto it = st.begin(); it != st.end(); ++it)
	{
		cout <<(*it).first<<" "<< it->second<<" " << endl;
	}
	cout << "------------------" << endl;
}

int main()
{    
	//建议1
	mapmp = { {2,10},{1,50},{3,8} };//利用初始化列表初始化
	Show(mp);
    //2
	mapmp1;//直接赋值 map[key]=value;
	mp1[2] = 20;
	mp1[3] = 50;
	mp1[0] = 9;
	mp1[int(4)] = 44;
	Show(mp1);
    //3
	mapmp2;//利用insert
	mp2.insert({ 1,1 });//建议
	mp2.insert(pair(2, 20));
	Show(mp2);

	return 0;

}

4.map的插入和删除

insert(elem);//在元素中插入元素elem
clear();//清楚所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一元素的迭代器
erase(beg,end);//删除区间[beg,end]的所有元素,返回下一个元素的迭代器
erase(key);//删除容器中值为key的元素
int main()
{    
	mapmp = { {2,10},{1,50},{3,8}};//利用初始化列表初始化
	mp.erase(2);//删除key为2的值
	Show(mp);
	//清空
	//mp.erase(mp.begin(), mp.end());
	mp.clear();
	return 0;
}

5.map查找和统计

find(key);//查找key是否存在,若存在返回该键的迭代器,不存在返回map.end()位置
count(key);//统计,查找键为 key 的键值对的个数并返回。对于map就是0或1
            //对于multimap就可能有多个
void Show(map& st)
{
	for (auto it = st.begin(); it != st.end(); ++it)
	{
		cout <<(*it).first<<" "<< it->second<<" " << endl;
	}
	cout << "------------------" << endl;
}

int main()
{    
	
	mapmp = { {2,10},{1,50},{3,8},{1,80} };//利用初始化列表初始化
	map::iterator it = mp.find(1);
	if (it != mp.end())
	{
		cout << "找到元素key:" << (*it).first <<" 找到元素:"<second<< endl;
	}
	else
		cout << "没找到元素" << endl;

	cout<

6.同set一般map的自定义排序(也可以自定义函数写或者仿函数)

sort排序不能针对关联容器(set,map),因为sort会破环关联容器的底层数据结构,详细解释如下。

map中的元素是pair类型对象,每个pair类型由关键字—值(key-value)组成:关键字起到索引的作用,值则表示与索引相关联的数据。字典是一个很好的map例子,可以将单词作为关键字,将单词释义作为值。
map使用的底层数据结构为一颗红黑树(红黑树是一颗高度平衡二叉排序树),因为map的各种操作接口,RB-Tree也都提供了,所以几乎所有的map操作行为,都只是转调用了RB-Tree的操作行为而已。TB-Tree中的key是按弱序排序的,因此map中的key也是按弱序排列的,所以任意更改map的key会严重破坏map组织的,也就是key不能修改(key也就不能使用sort排序。)
C++:map自定义排序
 

 C++ STL中Map的按Key排序和按Value排序_IIcyZhao的博客-CSDN博客_c++ map 按value排序

(map&C++)(五、排序)sort_lzh~的博客-CSDN博客_c++map sort

map容器的原型,默认的第三个参数其实是less,从小到大

使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。默认情况下,map 容器选用std::less排序规则(其中 T 表示键的数据类型),其会根据键的大小对所有键值对做升序排序。当然,根据实际情况的需要,我们可以手动指定 map 容器的排序规则,既可以选用 STL 标准库中提供的其它排序规则(比如std::greater),也可以自定义排序规则。

template < class Key,                                     // 指定键(key)的类型
           class T,                                       // 指定值(value)的类型
           class Compare = less,                     // 指定排序规则
           class Alloc = allocator >    // 指定分配器对象的类型
           > class map;
class test
{
public:
	bool operator()(int v1,int v2)const
	{
		return v1 > v2;
	}
};

bool mm(pair& m, pair& n) 全局才行,放在类里就要加static静态全局
{
	return m.second > n.second;
}
// 由于sort不能对map的second直接进行排序,故转化为pair进行排序,单调递减
	vector> mmp(mp.begin(), mp.end());
	sort(mmp.begin(), mmp.end(), mm);写成函数对象也可以

void Show(map& st)
{
	for (auto it = st.begin(); it != st.end(); ++it)
	{
		cout <<(*it).first<<" "<< it->second<<" " << endl;
	}
	cout << "------------------" << endl;
}

int main()
{    
	//从大到小排,与set使用相同
	//因为在创建容器时自动排序,因此要在创建的时候更改排序规则
	mapmp = { {2,10},{1,50},{3,8},{1,80} };//利用初始化列表初始化
    //等同于
    //map>mp = { {2,10},{1,50},{3,8},{1,80} };
	Show(mp);

	return 0;
}

map使用案例:

看懂敲一遍最好

#define 策划 0
#define 美术 1
#define 研发 2

class Worker {
public:
	string wokername;//员工姓名
	int salary;//工资
};
void CreateWorker(vector& ww) {
	string name = "ABCDEFGHIJ";
	for (int i = 0; i & mm, vector &ww) {
	//循环将员工插入容器
	for (vector::iterator it = ww.begin(); it != ww.end(); it++) {
		int number=rand() % 3;//0 1 2
		mm.insert({ number,*it });
	
	}
}
void Show(multimap& mm) {
	cout << "策划部门有:" << endl;
	multimap::iterator it=mm.find(策划);//找到部门为策划的第一个位置
	int index = 0;//设置索引
	for (it; it != mm.end() && index < mm.count(策划); index++, it++) {
		cout << "姓名:" << it->second.wokername << "  工资:" << it->second.salary << endl;
	}
	cout << "--------------------------------------------" << endl;

	cout << "美术部门有:" << endl;
	it = mm.find(美术);//找到部门为策划的第一个位置
	index = 0;//设置索引
	for (it; it != mm.end() && index < mm.count(美术); index++, it++) {
		cout << "姓名:" << it->second.wokername << "  工资:" << it->second.salary << endl;
	}
	cout << "--------------------------------------------" << endl;


	cout << "研发部门有:" << endl;
	it = mm.find(研发);//找到部门为策划的第一个位置
	index = 0;//设置索引
	for (it; it != mm.end() && index < mm.count(研发); index++, it++) {
		cout << "姓名:" << it->second.wokername << "  工资:" << it->second.salary << endl;
	}

}

int main()
{    
	srand((unsigned int)time(NULL));//随机数种子
	//创建10名员工
	vector ww;
	CreateWorker(ww);

	//将员工分组
	multimap mm;
	CapWorker(mm,ww);

	//分组打印
	Show(mm);
	return 0;
}

这一期就到此结束了,感谢观看,订阅此专栏。相关代码一定手撸一遍,加深记忆和理解。

大话STL第六期——map/multimap_第5张图片

你可能感兴趣的:(#,STL,c++,开发语言)