Map是标准关联式容器(associative container)之一,一个map是一个键值对序列,即(key ,value)对。它提供基于key的快速检索能力,在一个map中key值是惟一的。map提供双向迭代器,即有从前日后的(iterator),也有从后往前的(reverse_iterator)。ios
Map要求能对key进行<操做,且保持按key值递增有序,所以map上的迭代器也是递增有序的。若是对于元素并不须要保持有序,可使用hash_map。
数据库
Map中key值是惟一的,若是已存在一个键值对(name,code):("name_a",1),而咱们还想插入一个键值对("name_a",1)则会报错(不是报错,准确的说是,返回插入不成功!)。而咱们又的确想这样作,即一个键对应多个值,multimap可实现这个功能。
编程
Map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具备对数据自动排序的功能,因此在map内部全部的数据都是有序的,后边咱们会见识到有序的好处。
数组
因为STL是一个统一的总体,map的不少用法都和STL中其它的东西结合在一块儿,好比在排序上,默认用的是小于号,即less<>。 数据结构
Map中因为它内部有序,由红黑树保证,所以不少函数执行的时间复杂度都是log2N的,若是用map函数能够实现的功能,而STL Algorithm也能够完成该功能,建议用map自带函数,效率高一些。 less
Map在空间上的特性,因为map的每一个数据对应红黑树上的一个节点,这个节点在不保存你的数据时,是占用16个字节的,一个父节点指针,左右孩子指针,还有一个枚举值(标示红黑的,至关于平衡二叉树中的平衡因子),这些地方很费内存。函数
Map相似于数据库中的1:1关系,它是一种关联容器,提供一对一(C++ primer中文版中将第一个译为键,每一个键只能在map中出现一次,第二个被译为该键对应的值)的数据处理能力,这种特性了使得map相似于数据结构里的红黑二叉树。Multimap相似于数据库中的1:N关系,它是一种关联容器,提供一对多的数据处理能力。性能
a)、hash_map和map的区别在哪里?测试
(1)构造函数 hash_map须要hash函数,等于函数;map只须要比较函数(小于函数)。spa
(2)存储结构 hash_map采用hash表存储,map通常采用红黑树实现。所以内存数据结构是不同的。
b)、何时须要使用hash_map,何时须要map?
整体来讲,hash_map 查找速度会比map快,并且查找速度基本和数据数据量大小,属于常数级别;而map的查找速度是log(n)级别。
但若你对内存使用特别严格,但愿程序尽量少消耗内存,那么必定要当心,hash_map可能会让你陷入尴尬,特别是当你的hash_map对象特别多时,你就更没法控制了,并且 hash_map的构造速度较慢。
所以,选择的时候须要权衡三个因素: 查找速度,数据量,内存使用。
c)、如何用hash_map替换程序中已有的map容器?
这个很容易,但须要你有良好的编程风格。建议你尽可能使用typedef来定义你的类型:
typedef map KeyMap;
当你但愿使用hash_map来替换的时候,只须要修改:
typedef hash_map KeyMap;
其余的基本不变。固然,你须要注意是否有Key类型的hash函数和比较函数。
map(); // 默认构造函数 map(const map& m) // 拷贝构造函数 map(iterator begin, iterator end ); //区间构造函数 map(iterator begin, iterator end, const traits& _compare) //带比较谓词的构造函数 map(iterator begin, iterator end, const traits& _compare, const allocator& all) //带分配器
通过分析发现,map的构造函数主要是调用“拷贝构造函数”和利用“迭代器”进行初始化两种方式,由于map中每一个节点由一对值构成。
(1)、insert(pair<T1,T2,>(key1,value1)) //用insert函数插入pair数据 (2)、insert(map<T1,T2>::value_type(key1,value1)); //用insert函数插入value_type数据,这种插入方式和第一种基本类似 (3)、利用数组进行插入
示例:
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, “student_one”)); mapStudent.insert(pair<int, string>(2, “student_two”)); mapStudent.insert(pair<int, string>(3, “student_three”)); map<int, string>::iterator iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout<<iter->first<<” ”<<iter->second<<end; } }
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent.insert(map<int, string>::value_type (1, “student_one”)); mapStudent.insert(map<int, string>::value_type (2, “student_two”)); mapStudent.insert(map<int, string>::value_type (3, “student_three”)); map<int, string>::iterator iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout<<iter->first<<” ”<<iter->second<<end; } }
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent[1] = “student_one”; mapStudent[2] = “student_two”; mapStudent[3] = “student_three”; map<int, string>::iterator iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout<<iter->first<<” ”<<iter->second<<end; } }
以上三种用法,虽然均可以实现数据的插入,可是它们是有区别的:第一种和第二种在效果上是同样的,用insert函数插入数据,在数据的插入上涉及到集合的惟一性这个概念,即当map中有这个关键字时,insert操做是插入数据不了的,可是用数组方式就不一样了,它能够覆盖之前该关键字对应的值,以下:
mapStudent.insert(map<int, string>::value_type (1, “student_one”)); mapStudent.insert(map<int, string>::value_type (1, “student_two”));
上面这两条语句执行后,map中1这个关键字对应的值是“student_one”,第二条语句并无生效,那么咱们怎么知道insert语句是否插入成功,能够用pair来得到是否插入成功,程序以下:
Pair<map<int, string>::iterator, bool> Insert_Pair; Insert_Pair = mapStudent.insert(map<int, string>::value_type (1, “student_one”));
咱们经过pair的第二个变量来知道是否插入成功,它的第一个变量返回的是一个map的迭代器,若是插入成功的话:Insert_Pair.second应该是true的,不然为false。
下面给出完成代码,演示插入成功与否问题:
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; Pair<map<int, string>::iterator, bool> Insert_Pair; Insert_Pair=mapStudent.insert(pair<int, string>(1, “student_one”)); If(Insert_Pair.second == true) { Cout<<”Insert Successfully”<<endl; } Else { Cout<<”Insert Failure”<<endl; } Insert_Pair=mapStudent.insert(pair<int, string>(1, “student_two”)); If(Insert_Pair.second == true) { Cout<<”Insert Successfully”<<endl; } Else { Cout<<”Insert Failure”<<endl; } map<int, string>::iterator iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout<<iter->first<<” ”<<iter->second<<end; } }
用以下程序,看下用数组插入在数据覆盖上的效果:
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent[1] = “student_one”; mapStudent[1] = “student_two”; mapStudent[2] = “student_three”; map<int, string>::iterator iter; for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++) { Cout<<iter->first<<” ”<<iter->second<<end; } }
(1)、erase(map<T1,T2>::iterator iter); //删除迭代器所指的节点 (2)、erase(key k); //根据键值进行删除,删除键值k所指的节点 (3)、erase(map<T1,T2>::iteratormap iter1,<T1,T2>::iteratoriter2); //删除iter1和iter2之间的数据。 clear(); //清空map中的数据能够用clear()函数,断定map中是否有数据能够用empty()函数,它返回true则说明是空map
示例:
#pragma warning(disable:4786) #include <iostream> #include <string> #include <map> using namespace std; int main() { /* map<int,string> tmp; map<int,string>::const_iterator iter1,iter2; tmp.insert(pair<int,string>(54090104,"Bob")); tmp.insert(pair<int,string>(54090105,"Ben")); iter1 = tmp.begin(); iter2 = tmp.end(); */ map<int,string> studentMessage; map<int,string>::iterator iter; //向map中插入数据 studentMessage.insert(pair<int,string>(54090101,"Mike")); studentMessage.insert(pair<int,string>(54090101,"MIKE"));//重复插入 studentMessage.insert(map<int,string>::value_type(54090102,"Sam")); studentMessage.insert(map<int,string>::value_type(54090102,"SAM"));//重复插入 studentMessage[54090103] = "Jake"; studentMessage[54090103] = "JAKE";//重复插入 //为了测试删除,先插入两个数据,看插入结果主要看上面的插入方式 studentMessage[54090104] = "Bob"; studentMessage[54090105] = "Ben"; cout<<"完成插入后map中的数据:"<<endl; for(iter = studentMessage.begin() ; iter != studentMessage.end() ; ++iter) { cout<<iter->first<<" "<<iter->second<<endl; } //从map中删除数据 iter = studentMessage.begin(); studentMessage.erase(iter); cout<<"利用迭代器删除map中第一个元素:"<<endl; for(iter = studentMessage.begin() ; iter != studentMessage.end() ; ++iter) { cout<<iter->first<<" "<<iter->second<<endl; } studentMessage.erase(54090102); cout<<"利用键值删除map中的第一个元素:"<<endl; for(iter = studentMessage.begin() ; iter != studentMessage.end() ; ++iter) { cout<<iter->first<<" "<<iter->second<<endl; } studentMessage.erase(studentMessage.begin(),studentMessage.end()); cout<<"利用范围迭代器删除map中的全部数据:"<<endl; for(iter = studentMessage.begin() ; iter != studentMessage.end() ; ++iter) { cout<<iter->first<<" "<<iter->second<<endl; } return 0; }
begin(); //返回指向map头部的迭代器 end(); //返回指向map末尾的迭代器 (1)、count(); //用count函数来断定关键字是否出现,其缺点是没法定位数据出现位置,因为map的特性,一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1,出现的状况,固然是返回1了 (2)、find(); //用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,若是map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器 (3)、Lower_bound();Upper_bound(); //这个方法用来断定数据是否出现,是显得笨了点: //Lower_bound函数用法,这个函数用来返回要查找关键字的下界(是一个迭代器) //Upper_bound函数用法,这个函数用来返回要查找关键字的上界(是一个迭代器) //例如:map中已经插入了1,2,3,4的话,若是lower_bound(2)的话,返回的2,而upper-bound(2)的话,返回的就是3 Equal_range(); //函数返回一个pair,pair里面第一个变量是Lower_bound返回的迭代器,pair里面第二个迭代器是Upper_bound返回的迭代器,若是这两个迭代器相等的话,则说明map中不出现这个关键字
示例:
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, “student_one”)); mapStudent.insert(pair<int, string>(2, “student_two”)); mapStudent.insert(pair<int, string>(3, “student_three”)); map<int, string>::iterator iter; iter = mapStudent.find(1); if(iter != mapStudent.end()) { Cout<<”Find, the value is ”<<iter->second<<endl; } Else { Cout<<”Do not Find”<<endl; } }
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent[1] = “student_one”; mapStudent[3] = “student_three”; mapStudent[5] = “student_five”; map<int, string>::iterator iter; iter = mapStudent.lower_bound(2); { //返回的是下界3的迭代器 Cout<<iter->second<<endl; } iter = mapStudent.lower_bound(3); { //返回的是下界3的迭代器 Cout<<iter->second<<endl; } iter = mapStudent.upper_bound(2); { //返回的是上界3的迭代器 Cout<<iter->second<<endl; } iter = mapStudent.upper_bound(3); { //返回的是上界5的迭代器 Cout<<iter->second<<endl; } Pair<map<int, string>::iterator, map<int, string>::iterator> mapPair; mapPair = mapStudent.equal_range(2); if(mapPair.first == mapPair.second) { cout<<”Do not Find”<<endl; } Else { Cout<<”Find”<<endl; } mapPair = mapStudent.equal_range(3); if(mapPair.first == mapPair.second) { cout<<”Do not Find”<<endl; } Else { Cout<<”Find”<<endl; } }
max_size(); //返回map容器可能包含的元素最大个数 size(); //返回当前map容器中的元素个数 count(); //用来查找map中某个某个键值出现的次数;
示例:
#pragma warning (disable:4786) #include <map> #include <string> #include <iostream> using namespace std; int main() { map<int,string> studentMessage; map<int,string>::iterator iter; studentMessage.insert(pair<int , string>(54090101,"Mike")); studentMessage.insert(pair<int , string>(54090102,"Sam")); studentMessage.insert(pair<int , string>(54090103,"Jake")); //begin获取map中的第一个元素的迭代器,而且等于rend //end获取map中的最后一个元素下一位置的迭代器,而且等于rbegin cout<<"迭代器中的元素以下:"<<endl; for(iter = studentMessage.begin() ; iter != studentMessage.end() ; ++iter) { cout<<iter->first<<" "<<iter->second<<endl; } //看看max_size和size的值得意义 cout<<"map 的 max_size 的值:"<<studentMessage.max_size()<<endl; cout<<"map 的 size 的值:"<<studentMessage.size()<<endl; //看看empty和clear的使用 studentMessage.clear(); if(studentMessage.empty()) { cout<<"The map is Empty !!"<<endl; } else { cout<<"The map is not Empty !!"<<endl; } return 0; }
第一种:应用前向迭代器 第二种:应用反相迭代器 第三种:用数组方式
示例:
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, “student_one”)); mapStudent.insert(pair<int, string>(2, “student_two”)); mapStudent.insert(pair<int, string>(3, “student_three”)); map<int, string>::reverse_iterator iter; for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++) { Cout<<iter->first<<” ”<<iter->second<<end; } }
#include <map> #include <string> #include <iostream> Using namespace std; Int main() { Map<int, string> mapStudent; mapStudent.insert(pair<int, string>(1, “student_one”)); mapStudent.insert(pair<int, string>(2, “student_two”)); mapStudent.insert(pair<int, string>(3, “student_three”)); int nSize = mapStudent.size() //此处有误,应该是 for(int nIndex = 1; nIndex <= nSize; nIndex++) //by rainfish for(int nIndex = 0; nIndex < nSize; nIndex++) { Cout<<mapStudent[nIndex]<<end; } }
第一种:小于号重载 第二种:仿函数的应用,这个时候结构体中没有直接的小于号重载
示例:
#include <map> #include <string> Using namespace std; Typedef struct tagStudentInfo { Int nID; String strName; }StudentInfo, *PStudentInfo; //学生信息 Int main() { int nSize; //用学生信息映射分数 map<StudentInfo, int>mapStudent; map<StudentInfo, int>::iterator iter; StudentInfo studentInfo; studentInfo.nID = 1; studentInfo.strName = “student_one”; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); studentInfo.nID = 2; studentInfo.strName = “student_two”; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++) cout<<iter->first.nID<<endl<<iter->first.strName<<endl<<iter->second<<endl; } 以上程序是没法编译经过的,只要重载小于号,就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; //学生信息
#include <map> #include <string> Using namespace std; Typedef struct tagStudentInfo { Int nID; String strName; }StudentInfo, *PStudentInfo; //学生信息 Classs sort { Public: Bool operator() (StudentInfo const &_A, StudentInfo const &_B) const { If(_A.nID < _B.nID) return true; If(_A.nID == _B.nID) return _A.strName.compare(_B.strName) < 0; Return false; } }; Int main() { //用学生信息映射分数 Map<StudentInfo, int, sort>mapStudent; StudentInfo studentInfo; studentInfo.nID = 1; studentInfo.strName = “student_one”; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90)); studentInfo.nID = 2; studentInfo.strName = “student_two”; mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80)); }