一、简介map

我们与最常用的数组作比较

  • 1、数组我们都得有确定的长度,而map你可以随意删除和插入数据,它的长度是根据用户的操作动态变化的
  • 2、我们通过数组的下标来访问数组元素,而下标i必须是整形,而map的下标的数据类型是用户自己定义的,例如先定义一个以char类型为下标,里面存的int型的map:map<char, int> M,再插入数据:M['a']=5; 此时访问M['a'] 就会输出5。
  • 3、无论是数组,还是map都是下标与元素之间都是映射的,也就是说下标不能重复,下标我们称之为键值key,里面存放的值我们称之为value,为什么不能重复,那数组来做比较,比如a[1]=1,a[2]=2,你的下标(key)只能对应一个值(value),而一个值可以对应多个下标,如a[1]=3 , a[2]=3,我们称之为映射
  • 迭代器:map<int,string>::iterator it; 此时it相当于数组的下标,不过不能直接访问it,因为it是一个地址,分别用it->first和it->second来访问int和string

 

二、map最基本的构造函数:map<key, value> M;

map<string ,int> M; 
map<int,string > M;
map<sring,char>  M;
map<char,string> M;
逗号前面的数据类型是下标,后面的数据类型是存储
此时M是空,如果不是空,我们可以通过M[key]访问key对应的value

 

三、map元素的插入,以 map<int,string > M; 为例

1. M[112]="April";//map中最简单最常用的插入添加!
2. M.insert(pair<int,string> (102,"aclive"));
3. M.insert(map<int,string>::value_type(321,"hai"));

最常用的就是第一种了,时间是线性的

 

四、map元素的遍历

#include<bits/stdc++.h> 
using namespace std;
map<int,string> M;
int main()
{
	map<int,string>::iterator it;
	M[1]=" ";
	M[2]="you ";
	M[3]="baby";
	for(it=M.begin();it!=M.end();it++)
	cout<<it->second;
	
	for(int i=1;i<=3;i++)
	cout<<M[i];
}

 

五、map元素的查找

#include<bits/stdc++.h> 
using namespace std;
map<int,string> M;
int main()
{
	M[1]= ";
	M[2]="you ";
	M[3]="baby ";
	map<int,string>::iterator it;
	
	it=M.find(1);
	
	cout<<it->second;
}

find函数返回的是一个迭代器,如果没找到这个元素,返回的是M.end(),一般用不着,因为只能通过下标key查找值value,而我们可以直接通过M[key] 访问元素value,通常find函数是用来判断map里面是否有这个元素,

 

六、map元素的删除

#include<bits/stdc++.h> 
using namespace std;
map<int,string> M;
int main()
{
	M[1]=" ";
	M[2]="you ";
	M[3]="baby ";
	map<int,string>::iterator it;
	
	it=M.find(1);
	if(it!=M.end()) M.erase(it);
	//通过迭代器删除 
	
}

这个例子是删除M[1],先查找M[1]再删除

 

七、其他的操作

  1.      begin()                       返回指向map头部的迭代器
  2.      clear()                      删除所有元素
  3.      count()                       返回指定元素出现的次数
  4.      empty()                      如果map为空则返回true
  5.      end()                          返回指向map末尾的迭代器
  6.      equal_range()           返回特殊条目的迭代器对
  7.      erase()                       删除一个元素
  8.      find()                          查找一个元素
  9.      get_allocator()          返回map的配置器
  10.      insert()                       插入元素
  11.      key_comp()               返回比较元素key的函数
  12.      lower_bound()          返回键值>=给定元素的第一个位置
  13.      max_size()                返回可以容纳的最大元素个数
  14.      rbegin()                     返回一个指向map尾部的逆向迭代器
  15.      rend()                        返回一个指向map头部的逆向迭代器
  16.      size()                         返回map中元素的个数
  17.      swap()                       交换两个map
  18.      upper_bound()         返回键值>给定元素的第一个位置
  19.      value_comp()           返回比较元素value的函数

 

七、unordered_map

unordered_map与map的所有操作都是一样的,只不过两者在底层构造有所差别

map: map内部实现了一个红黑树(红黑树是非严格平衡二叉搜索树,而AVL是严格平衡二叉搜索树),红黑树具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素。因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行的操作。map中的元素是按照二叉搜索树(又名二叉查找树、二叉排序树,特点就是左子树上所有节点的键值都小于根节点的键值,右子树所有节点的键值都大于根节点的键值)存储的,使用中序遍历可将键值按照从小到大遍历出来。

unordered_map: unordered_map内部实现了一个哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。

 

优缺点以及适用处
map:

  1. 有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作
  2. 红黑树,内部实现一个红黑书使得map的很多操作在lgn的时间复杂度下就可以实现,因此效率非常的高
  3. 缺点: 空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间

适用处:对于那些有顺序要求的问题,用map会更高效一些

unordered_map:

  1. 优点: 因为内部实现了哈希表,因此其查找速度非常的快
  2. 缺点: 哈希表的建立比较耗费时间, 也没有排序

适用处:对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map

 

内存占有率的问题就转化成红黑树 VS hash表 , 还是unorder_map占用的内存要高。但是unordered_map执行效率要比map高很多。

对于unordered_map或unordered_set容器,其遍历顺序与创建该容器时输入的顺序不一定相同,因为遍历是按照哈希表从前往后依次遍历的