欢迎前往我的个人博客阅读原文。
类似于 python 中的字典,map 映照容器的元素数据是由一个键值和一个映照数据组成的,键值与映照数据之间具有一一映照的关系。
map 映照容器插入元素的键值不允许重复,比较函数只对元素的键值进行比较,元素的各项数据可通过键值检索出来。(map 映照容器的数据结构是采用红黑树来实现的,看来要补充的知识好多)。
使用 map 容器需要头文件包含语句:
#include<map>
map 创建、元素插入和遍历访问
创建 map 对象,键值与映照数据的类型由自己定义。在没有指定比较函数的情况下,元素的插入位置是按键值由小到大插入到红黑树中。
#include<map>
#include<string>
#include<iostream>
using namespace std;
int main(int argc, char* argv[])
{
// 定义 map 对象,当前没有任何元素
map<string, float> m;
// 插入元素,按键值由小到大放入红黑树中
m["Tsui"] = 98.5;
m["Joshua"] = 96.0;
m["Kristopher"] = 97.5;
// 前向遍历元素
map<string, float>::iterator it;
for (it = m.begin(); it != m.end(); it++)
{
// 输出键值与映照数据
cout << (*it).first << " : " << (*it).second << endl;
}
return 0;
}
运行结果:
容易从结果看出是按照字母顺序排列的,即按键值由小到大排列的。
删除元素
和前面学习的一样,map 映照容器删除元素也是使用 erase()
函数来实现的。它可以删除某个迭代器位置上的元素、等于某个键值的元素或者一个迭代器区间上的所有元素。当然,也和前面一样,可以使用 clear()
方法清空 map 映照容器。
#include<map>
#include<iostream>
using namespace std;
int main(int argc, char* argv[])
{
map<int, char> m;
m[2] = 's';
m[3] = 'u';
m[1] = 't';
m[4] = 'i';
// 删除键值为 3 的元素
m.erase(3);
map<int, char>::iterator it;
for (it = m.begin(); it != m.end(); it++)
cout << (*it).first << " : " << (*it).second << endl;
return 0;
}
运行结果:
元素反向遍历
可以使用反向迭代器 reverse_iterator
反向遍历 map 映照容器中的数据,这里还需要使用 rbegin()
方法 rend()
方法指出反向遍历的起始位置和终止位置。
#include<map>
#include<iostream>
using namespace std;
int main(int argc, char* argv[])
{
map<int, char> m;
m[2] = 's';
m[3] = 'u';
m[1] = 't';
m[4] = 'i';
// 反向遍历元素
map<int, char>::reverse_iterator rit;
for (rit = m.rbegin(); rit != m.rend(); rit++)
cout << (*rit).first << " : " << (*rit).second << endl;
return 0;
}
运行结果:
元素的搜索
搜索依旧使用的是 find()
方法。使用 find()
方法搜索某个键值,如果搜索到了,则返回该键值所在的迭代器位置,否则,返回 end()
迭代器位置。例如:
#include<map>
#include<iostream>
using namespace std;
int main(int argc, char* argv[])
{
map<int, char> m;
m[2] = 's';
m[3] = 'u';
m[1] = 't';
m[4] = 'i';
map<int, char>::iterator it;
// 搜索键值为 3 的元素
it = m.find(3);
// 搜索到该键值
if (it != m.end())
cout << (*it).first << " : " << (*it).second << endl;
else
cout << "not find it" << endl;
return 0;
}
运行结果:
自定义比较函数
将元素插入到 map 中去时,map 会根据设定的比较函数将该元素放到该放的节点上。在定义 map 的时候,如果没有指定比较函数,那么将采用默认的比较函数,即按照键值由小到大的顺序插入元素。编写比较函数的方法有两种:
- 如果元素不是结构体,那么,可以编写比较函数。下面这段程序编写的比较规则是按照键值由大到小的顺序将元素插入到 map 中:
#include<map>
#include<iostream>
using namespace std;
// 自定义比较函数 myComp
struct myComp
{
bool operator()(const int &a, const int &b)
{
if (a != b)
return a > b;
else
return a > b;
}
};
int main(int argc, char* argv[])
{
map<int, char, myComp> m;
m[2] = 's';
m[3] = 'u';
m[1] = 't';
m[4] = 'i';
// 使用前向迭代器中序遍历 map
map<int, char, myComp>::iterator it;
for (it = m.begin(); it != m.end(); it++)
cout << (*it).first << " : " << (*it).second << endl;
return 0;
}
运行结果:
- 如果元素是结构体,那么,可以直接把比较函数写在结构体内。
#include<map>
#include<string>
#include<iostream>
using namespace std;
struct Info
{
string name;
float score;
// 重载 "<" 操作符,自定义排序规则
bool operator < (const Info &a) const
{
// 按 score 由大到小排列。如果要由小到大排列,使用">"号即可
return a.score < score;
}
};
int main(int argc, char* argv[])
{
map<Info, int> m;
// 定义 Info 结构体变量
Info info;
info.name = "Joshua";
info.score = 60;
m[info] = 25;
info.name = "Tsui";
info.score = 80;
m[info] = 10;
info.name = "Kristopher";
info.score = 66.5;
m[info] = 30;
map<Info, int>::iterator it;
for (it = m.begin(); it != m.end(); it++)
{
cout << (*it).second << " : ";
cout << ((*it).first).name << ' ' << ((*it).first).score << endl;
}
return 0;
}
运行结果:
map 映照容器的基本知识就到这里,另外需要注意的是,程序编译时,可能会产生代号为 “warning C4786” 的警告。“4786” 是标记符超长警告的代号。可以在程序的头文件代码前面使用 #pragma warning(disable:4786)
宏语句,强制编译器忽略该警告。4786 号警告对程序的正确性和运行并无影响。