本节中,我们来学习map/multimap容器 (在STL中,map容器具有高效率,高性能的称呼!)
map/multimap容器可以用于:在大量的数据当中找到你想要的某一个数据,比如通过一个身份证号码在全中国那么多人中找到一个人
这个容器和python中的字典数据类型是一毛一样的!
map/multimap 这个容器的使用频率是仅次于 vector容器 和 list容器的,我们要熟练掌握!
在STL中,map的地位还是比较高的!
简介:
map中all的元素都是pair(也即map中all的元素都是两两成对出现的)
pair中第一个元素为key(键值),起到的是索引的作用,第二个元素为value(实值)
(这个索引的作用的意思是:就比如学号1,表示张三,学号2表示李四,那么这个学号就起到了索引的作用!)
所有的元素都会根据元素的key键值 进行自动排序
(也即你在插入元素的同时,它就会按照key值给你排序好)
本质:
map/multimap容器也属于关联式的容器,底层结构也是 用 二叉树 实现的(set/multiset的底层也是用二叉树来实现的)
(所谓关联式容器的意思,就是你无序地插入数据后,该容器会给你自动的排好序)
(注意:这是按照key键值来排序,而不是按照value实值来排序的!)
优点:
可以根据key值快速地找到value值
map and multimap 容器的区别:(可以类比 set and multiset容器的区别)
map不允许容器中有重复的key值元素(当然,value值肯定是允许重复出现的)
(也即对于map容器的对象,你想插入重复key值的pair对组元素都是插不了的!插入了也毫无意义!也不会显示出来)
multimap允许容器中有重复的key值元素(value值肯定是允许重复出现的)
一、map的构造和赋值(当然,multimap也是类似的同理的)
功能描述:
对map容器进行构造和赋值操作
函数原型:
构造:
(map的模板参数列表中是含有2个模板参数T1和T2的)
map<T1,T2> mp;//map的默认构造函数
map(const map& mp);//拷贝构造函数
赋值:
map& operator=(const map&mp); //重载等号操作符
(也利用了重载函数时 链式编程的思想)
总结:
map/multimap容器中所有的元素都是成对出现的,插入数据的时候需要使用对组pair这种数据结构噢(你来个匿名的对组对象即可)
二、map的大小和交换操作(当然,multimap也是类似的同理的)
功能描述:
统计map容器大小以及交换map容器对象的数据
函数原型:
size();//返回容器中元素的数目(也即返回容器的大小)
empty();//判断容器是否为空(空--返回真true 非空--返回假false)
swap(mp); //交换两个map容器对象中的数据
总结:
统计大小 --- .size()
判断是否为空 ---.empty()
交换容器 ---.swap()
三、map的插入和删除操作(当然,multimap也是类似的同理的)
功能描述:
map容器进行插入数据和删除数据
函数原型:
insert(elem); //在容器中插入pair类型的元素elem
clear();
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg,end); //删除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(key); //删除容器中 键值为key的元素
(只会按照key值来删除,而不会按照value值来删除)
注意:
[]不建议用来do插入,但你大可以用mapName[key]:利用key来访问到value
第一种插入方式:(最好这第一种还有第二种)
mp.insert(pair<int, string>(1, "lzf"));
第二种插入方式:
mp.insert(make_pair(5, "zzl"));
第三种插入方式:(最好不要记了!太长了!)
mp.insert(map<int, string>::value_type(6, "zzh"));
第四种插入方式:(这种方式是最不好的!)
mp[7] = "trtjq4";
[]一般用来访问数据就比较好!
总结:
map插入的方式有很多,记住其中一个即可
map.insert(pair<int,int>(1,10));//这种我用的最熟悉!
插入 --- insert
删除 --- erase
清空 --- clear
四、map的查找和统计操作(当然,multimap也是类似的同理的)
功能描述:
对map容器进行查找数据以及统计数据
函数原型:
find(key); //查找键值key是否存在,若一旦找到了,也即其存在,则返回该键的元素的迭代器(这里是返回 一碰到它key存在的那个元素(第一个碰到的),就返回该元素的迭代器了);若不存在,则返回map.end();
(不论你有没有查到这个key值所对应的元素,find都会返回该容器对应的一个迭代器,so你必须要拿一个迭代器去接受find函数的结果)
count(key);//统计键值为key的元素的个数
总结:
查找 --- find(返回的是迭代器)
统计 --- count(对于map容器,结果为0or1,但是对于multimap容器而言,结果可以大于1)
(因为map容器不允许出现重复key值的元素,但是multimap容器是允许出现重复key值的元素的)
五、map容器的排序操作(当然,multimap也是类似的同理的)
map<T1,T2,仿函数名> mp;//通过加入第三个模板参数从而使得map/multimap容器可以进行我自定义的排序
当然,如果你在map/multimap中加入的是自定义的数据类型,那么就必须要指定排序规则!
注意:对于关联式容器,必须要使用仿函数来改变高级排序的规则
学习目标:
map容器默认的排序规则为: 按照key值进行 从小到大的排序(也即升序),我们需要去掌握如何改变排序规则
主要的技术点:
利用仿函数,可以改变排序的规则
(所谓的仿函数,其实就是在一个类中去重载 调用函数的符号() ,并且该函数的返回值还必须是bool的类型)
注意!set/multiset容器可以按照你自定义类型中的成员属性来排序,但是map/multimap容器就不行,就必须要按照你的pair中的key值来排序!
总结:
利用仿函数可以指定map容器的排序规则
对于自定义的数据类型,map/multimap必须要指定排序的规则,同set/multiset
test_codes:
#include<iostream>
#include<map>
#include<string>
using namespace std;
void printMultimap(const multimap<int, int>& mmp);
class myCompare
{
public:
bool operator()(int val1,int val2)
//!!!注意:你pair<T1,T2> p;//中的T1 和 T2 是什么类型,仿函数中的元素就是什么类型
{
//升序
return val1 > val2;
}
};
class myCompare2
{
public:
bool operator()(double val1, double val2)
//!!!注意:你pair<T1,T2> p;//中的T1 和 T2 是什么类型,仿函数中的元素就是什么类型
{
//升序
return val1 > val2;
}
};
void PrintMap(const map<int, int, myCompare>& mp)
{
for (map<int, int, myCompare>::const_iterator it = mp.begin();it != mp.end();it++) {
cout << "key = " << it->first << "\tvalue = " << it->second << endl;
}
cout << endl;
}
void PrintMultimap(const multimap<double, string, myCompare2>& mmp)
{
for (multimap<double, string, myCompare2>::const_iterator it = mmp.begin();it != mmp.end();it++)
{
cout << "key = " << it->first << "\tvalue = " << it->second << endl;
}
cout << endl;
}
class Person
{
public:
//构造函数
Person(int age, string name) :m_Age(age), m_Name(name) {};
int m_Age;
string m_Name;
};
class myCompare3
{
public:
bool operator()(const Person&p1, const Person&p2)
{
return p1.m_Age > p2.m_Age;
}
};
void printmultimap(const multimap<int, Person, myCompare>& mmp)
{
for (multimap<int, Person, myCompare>::const_iterator it = mmp.begin();it != mmp.end();it++) {
cout << "key = " << it->first << "\tvalue: 年龄:" << it->second.m_Age << "\t姓名:" << it->second.m_Name << endl;
}
cout << endl;
}
//void prinTMultimap(const multimap<Person, int>& mmp)
//{
// for (multimap<Person, int>::const_iterator it = mmp.begin();it != mmp.end();it++) {
// cout << "key_age :" << it->first.m_Age << "\tkey_name :" << it->first.m_Name << "\tvalue: " << it->second << endl;
// }
// cout << endl;
//}
void test5()
{
//map<int, int,myCompare>mp;
//typedef pair<int, int>TNAME;
//mp.insert(TNAME(1, 10));
//mp.insert(TNAME(2, 20));
//mp.insert(TNAME(4, 30));
//mp.insert(TNAME(3, 30));
//PrintMap(mp);
//multimap<double, string, myCompare2> mmp;
//typedef pair < double, string > TypeName;
//mmp.insert(TypeName(1.1, "lzf"));
//mmp.insert(TypeName(4.4, "zhf"));
//mmp.insert(TypeName(2.2, "trf"));
//mmp.insert(TypeName(3.3, "lyf"));
//PrintMultimap(mmp);
//multimap<int, Person, myCompare> mmp1;
准备数据
//Person p1(23, "lzf");
//Person p2(21, "trf");
//Person p3(33, "lyf");
//Person p4(25, "zhhf");
插入函数自定义数据类型的元素
//mmp1.insert(make_pair(1, p1));
//mmp1.insert(make_pair(2, p2));
//mmp1.insert(make_pair(3, p3));
//mmp1.insert(pair<int, Person>(4, p4));
//printmultimap(mmp1);
multimap<Person, int> mmp2;
mmp2.insert(pair<Person,int>(p1,1));
why 自定义的数据类型不能放在对组pair的模板参数的前面呢?
mmp2.insert(make_pair(p2, 2));
mmp2.insert(make_pair(p3, 3));
mmp2.insert(make_pair(p4, 4));
prinTMultimap(mmp2);
//string s = "fanfan";
//int as = 27;
//pair<int, string >pm;
//pm = make_pair(as, s);
//cout << pm.first << endl;
//cout << pm.second << endl;
//pair<int, string> getPerson();
//string name;
//int age;
//tie(name, age) = getPerson();
//cout << "name: " << name << ",age: " << age << endl;
}
//以pair对象做为函数返回值
pair<int, string> getPerson() {
return make_pair(25, "Sven");
}
void test4()
{
multimap<int, int> mmp;
mmp.insert(pair<int, int>(1, 10));
mmp.insert(pair<int, int>(3, 30));
mmp.insert(pair<int, int>(4, 40));
mmp.insert(pair<int, int>(2, 20));
mmp.insert(pair<int, int>(1, 10));
mmp.insert(pair<int, int>(1, 10));
mmp.insert(pair<int, int>(1, 10));
printMultimap(mmp);
multimap<int, int>::iterator pos = mmp.find( 1);
if (pos != mmp.end()) {
cout << "找到该元素了,key = " << (*pos).first <<"\tvalue = " <<pos->second<<"了"<<endl;
}
else {
cout << "找不到该元素!" << endl;
}
cout << endl;
cout << "key值为1的元素有" <<mmp.count(1)<< "个" << endl;
cout << "key值为2的元素有" << mmp.count(2) << "个" << endl;
}
void printMap(const map<int, string>& mp)
{
for (map<int, string>::const_iterator it = mp.begin();it != mp.end();it++) {
cout << "学号:" << it->first << "\t姓名:" << it->second << endl;
}
cout << endl;
}
void printMultimap(const multimap<int, int>& mmp)
{
for (multimap<int, int>::const_iterator it = mmp.begin();it != mmp.end();it++) {
cout << "key = " << it->first << "\tvalue = " << it->second << endl;
}
cout << endl;
}
void test3()
{
map<int, string> mp;
//第一种插入方式:(最好这第一种还有第二种)
mp.insert(pair<int, string>(1, "lzf"));
mp.insert(pair<int, string>(2, "lyf"));
mp.insert(pair<int, string>(4, "tjf"));
mp.insert(pair<int, string>(3, "zhb"));
//第二种插入方式:
mp.insert(make_pair(5, "zzl"));
//第三种插入方式:(最好不要记了! )
mp.insert(map<int, string>::value_type(6, "zzh"));
//第四种插入方式:(这种方式是最不好的!)
mp[7] = "trtjq4";
cout << mp[8] << endl;
//但是如果你不小心弄错了,输出了不存在的map容器对象的位置元素,那么这个元素(if为字符or字符串类型的话)则默认为空(if为数值型数据则默认为0)
printMap(mp);
map<int, string>::iterator it = mp.begin();
//删除map容器开头处的元素
//mp.erase(it);
//printMap(mp);
cout << "删除key值为3的数据后,mp: " << endl;
mp.erase(3);
printMap(mp);
//mp.erase(mp.begin(), mp.end());//<=> mp.clear();
mp.clear();
printMap(mp);
multimap<int, int> mmp;
mmp.insert(pair<int, int>(1, 10));
mmp.insert(pair<int, int>(3, 30));
mmp.insert(pair<int, int>(2, 20));
mmp.insert(pair<int, int>(4, 40));
printMultimap(mmp);
mmp.erase(2);
mmp.erase(30);//你是删除不了value值为30的元素的,erase只能
printMultimap(mmp);
}
void printMAP(const map<int, string>& mp)
{
for (map<int, string>::const_iterator it = mp.begin();it != mp.end();it++) {
cout << "key: " << it->first << "\tvalue: " << (*it).second << endl;
}
cout << endl;
}
void printMULTIMAP(const multimap<string, string>&mmp)
{
for (multimap<string, string>::const_iterator it = mmp.begin();it != mmp.end();it++) {
cout << "key: " << it->first << "\tvalue: " << it->second << endl;
}
cout << endl;
}
void test2()
{
map<int, string> mp;
mp.insert(pair<int, string>(1, "林卓凡"));
mp.insert(pair<int, string>(2, "lyf"));
mp.insert(pair<int, string>(3, "tjr"));
cout << "mp容器对象的大小:"<<mp.size() << endl;
map<int, string> mp2=mp;
if (mp2.empty()) {
cout << "mp2为空!" << endl;
}
else {
cout << "mp2不为空!" << endl;
cout << "mp2的大小为:" << mp2.size() << endl;
cout << "mp2:" << endl;
printMAP(mp2);
}
cout << "swap前:" << endl;
cout << "mp:" << endl;
printMAP(mp);
cout << "mp2:" << endl;
printMAP(mp2);
mp2.swap(mp);
cout << "swap后:" << endl;
cout << "mp:" << endl;
printMAP(mp);
cout << "mp2:" << endl;
printMAP(mp2);
multimap<string, string> mmp;
mmp.insert( pair<string, string>("1", "lzf") );
mmp.insert( pair<string, string>("2", "lyf") );
mmp.insert( pair<string, string>("2", "tjr") );
printMULTIMAP(mmp);
if (mmp.empty()) {
cout << "mmp为空!" << endl;
}
else {
cout << "mmp不为空!" << endl;
cout << "mmp: " << endl;
printMULTIMAP(mmp);
}
multimap<string, string>mmp2;
cout << "swap前:" << endl;
cout << "mmp:" << endl;
printMULTIMAP(mmp);
cout << "mmp2:" << endl;
printMULTIMAP(mmp2);
mmp2.swap(mmp);
cout << "swap后:" << endl;
cout << "mmp:" << endl;
printMULTIMAP(mmp);
cout << "mmp2:" << endl;
printMULTIMAP(mmp2);
}
void(*pt1)() = test1;
void(*pt2)() = test2;
void(*pt3)() = test3;
void(*pt4)() = test4;
void(*pt5)() = test5;
int main()
{
(*pt5)();
system("pause");
return 0;
}