一. 简介
- map是STL 的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。
- map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
- map 是一种有序无重复的关联容器。关联容器与顺序容器不同,他们的元素是按照关键字来保存和访问的,而顺序元素是按照它们在容器中的位置保存和访问的。map保存的是一种 key - value 的pair对象,其中 key 是关键字,value 是关键字对应的值。通过 key找到对应的 value。map中按照 key的大小升序排列pair对象。map会自动建立Key - value的对应。
二. 用法
1. 头文件
#include
2. 构造函数
//在定义map对象时,必须分别指明键和值的类型。Map建立key-value的一种映射。
//创建一个名为m的空map对象,其键和值的类型分别为key和value
map m;
//创建m2的副本m,m与m2必须有相同的键类型和值类型
map m(m2);
//创建map类型的对象m,存储迭代器b和e标记的范围内所有元素的副本,元素的类型必须能转换为pair
map m(b,e);
//comp可选,键值对存放策略
map mp;
3. map定义的类型
// 在map容器中,用作索引的键的类型
map ::key_type;
// 在map容器中,键所关联的值的类型
map ::mapped_type;
// 一个pair类型,它的first元素具有const map ::key_type类型,而second元素则xmap :: mapped_type类型。
map ::value_type;
在学习map接口时,谨记其value_type是pair类型,它的值成员可以修改(second成员),但键成员不能修改。这个value_type相当于map的元素类型,而不是键所对应的值的类型。
对map迭代器进行解引用将产生pair类型的对象,它的first成员存放键,为const,而second成员存放值。
4. 插入数据
①用insert函数插入pair数据
m.insert(pair(1, "student_one"));
make_pair()//返回类型为对应的pair类型
无需写出类别,就可以生成一个pair对象
例:
make_pair(1,'@')
而不必费力的写成
pair(1,'@')
②用insert函数插入value_type数据
m.insert(map::value_type (1, "student_one"));
③数组插入方式
#include
5. map的大小
m.size()查看
6. 数据的遍历
①应用前向迭代器
例如4-③中的例子
②应用反向迭代器
#include
③用数组方式
#include
7. 数据的查找
#include
8. 排序
#include
以上程序是无法编译通过的,只要重载小于号,就OK了,如下:
Typedef struct tagStudentInfo
{
int nID;
String strName;
Bool operator < (tagStudentInfo const& _A) const
{
//这个函数指定排序策略,按nID排序,如果nID相等的话,按strName排序
If(nID < _A.nID) return true;
If(nID == _A.nID) return strName.compare(_A.strName) < 0;
Return false;
}
}StudentInfo, *PStudentInfo; //学生信息
三. multimap
- multimap 与 map 一样,都是使用红黑树对记录型的元素数据,按元素键值的比较关系,进行快速的插入、删除和检索操作。
- 所不同的是 multimap 允许将具有重复键值的元素插入容器。在 multimap 容器中,元素的键值与元素的映照数据的映照关系,是多对多的,因此,multimap 称为多重映照容器。
- multimap 与 map 之间的多重特性差异,类似于 multiset 与 set 的多重特性差异。
- multimap 多重映照容器实现了 Sorted Associative Container 、Pair Associative Container 和 Multimap Associative Container 概念的接口规范。
- 一些说明:
/*
*
********************************************
* multimap多重映照容器的基础说明:
********************************************
*
* multimap多重映照容器:容器的数据结构采用红黑树进行管理
* multimap的所有元素都是pair:第一元素为键值(key),不能修改;第二元素为实值(value),可被修改
*
* multimap特性以及用法与map完全相同,唯一的差别在于:
* 允许重复键值的元素插入容器(使用了RB-Tree的insert_equal函数)
* 因此:
* 键值key与元素value的映照关系是多对多的关系
* 没有定义[]操作运算
*
* Sorted Associative Container Pair Associative Container Unique Associative Container
*
* 使用multimap必须使用宏语句#include
#include
四. hash_map
- hash_map的用法和map是一样的,提供了 insert,size,count等操作,并且里面的元素也是以pair类型来存贮的。
- 虽然对外部提供的函数和数据类型是一致的,但是其底层实现是完全不同的,map底层的数据结构是红黑树,hansh_map却是哈希表来实现的。
- 总体来说,hash_map 查找速度会比map快,而且查找速度基本和数据量大小无关,属于常数级别;而map的查找速度是log(n)级别。hash还有hash函数的耗时。当有100w条记录的时候,map也只需要20次的比较,200w也只需要21次的比较!所以并不一定常数就比log(n) 小!
- hash_map对空间的要求要比map高很多,所以是以空间换时间的方法,而且,hash_map如果hash函数和hash因子选择不好的话,也许不会达到你要的效果。所以用map,还是hash_map,从3个方面来权衡: 查找速度、数据量、内存使用。
- 另外可以通过重写 hash_compair仿函数,更改里面关于桶数量的定义,如果取值合适,也可以得到更优的性能。而且如果你的数据是自定义的类型,必须要重写这个仿函数。可以模仿原来的写法,所有的成员函数,成员变量一个不能少!
- 另外再有两篇参考文章:
hash_map (STL/CLR)【微软STL文档】
[Z]C++ STL中哈希表 hash_map介绍
五. unordered_map
- hash_map并非标准STL中的,VS直接#include会提醒你这个库可能变化比较大,建议你换用其他的。所以现在比较常用的是类似的unordered_map。
- hash_map内部是一个hash_table一般是由一个大vector,vector元素节点可挂接链表来解决冲突,来实现。

- unordered_map需要定义hash_value函数并且重载operator==。对于内置类型,如string,这些都不用操心。对于自定义的类型做key,就需要自己重载operator< 或者hash_value()了。
#include
#include
#include
using namespace std;
/*
一个应用哈希表的例子:
查找一个字符串中第一个只出现一次的数
*/
int main() {
string in = "abcdefabcdf";
unordered_map hashtable;
for (int i = 0; i < in.length(); i++) {
//key是每一个字符,value是出现次数
unordered_map::iterator one;
one = hashtable.find(in[i]);
//如果没有,直接插入,并且标记为1
if (one == hashtable.end()) {
hashtable.insert(make_pair(in[i], 1));
}
//如果有,该位置加一
else {
one->second = one->second + 1;
}
}
//查找并输出
for (unordered_map::iterator i = hashtable.begin(); i != hashtable.end(); i++) {
if (i->second == 1) {
cout << i->first << endl;
break;
}
}
getchar();
return 0;
}