Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据 处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
1、map简介
map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。
对于迭代器来说,可以修改实值,而不能修改key。
2、map的功能
自动建立Key - value的对应。key 和 value可以是任意你需要的类型。
根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
快速插入Key -Value 记录。
快速删除记录
根据Key 修改value记录。
遍历所有记录。
3、使用map
使用map得包含map类所在的头文件
#include <map> //注意,STL头文件没有扩展名.h
map对象是模板类,需要关键字和存储对象两个模板参数:
std:map<int,string> personnel;
这样就定义了一个用int作为索引,并拥有相关联的指向string的指针.
为了使用方便,可以对模板类进行一下类型定义,
typedef map<int,CString> UDT_MAP_INT_CSTRING;
UDT_MAP_INT_CSTRING enumMap;
4、map的插入
以下三种用法,虽然都可以实现数据的插入,但是它们是有区别的,用insert函数插入数据,在数据的 插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,insert操作是插入数据不了的,但是用数组方式就不同了,它可以覆盖以前该关键字对 应的值
#include <map>
#include <string>
#include <iostream>
using namespace std;
typedef map<int, string> UDT_MAP_INT_STRING;
typedef map<string, string> UDT_MAP_STR_STRING;
int main()
{
map<int, string> mapStudent;
UDT_MAP_STR_STRING mapStr;
// 三种插入方式
mapStudent[1] = "student_one"; // 可以覆盖
mapStudent.insert(pair<int, string>(2, "student_two")); // 唯一性
mapStudent.insert(map<int, string>::value_type (3, "student_three")); // 唯一性
// 判定是否插入成功
//pair<map<int, string>::iterator, bool> Insert_Pair;
pair<UDT_MAP_INT_STRING::iterator, bool> Insert_Pair;
Insert_Pair = mapStudent.insert(pair<int, string>(1, "student_one"));
if (Insert_Pair.second)
cout << "Insert Successfully" << endl;
else
cout << "Insert Failure" << endl;
cout << "--------------" << endl;
mapStr["tom"] = "tomcate";
mapStr.insert(pair<string, string>("kit", "kitty"));
mapStr.insert(UDT_MAP_STR_STRING::value_type ("cob", "cobben"));
UDT_MAP_STR_STRING::iterator siter;
for(siter = mapStr.begin(); siter != mapStr.end(); siter++)
cout << siter->first << " " << siter->second << endl;
cout << "--------------" << endl;
// 查看map中元素个数
int nSize = mapStudent.size();
cout << "mapStudent numbers: " << nSize << endl;
nSize = mapStr.size();
cout << "mapStr numbers: " << nSize << endl;
// 三种数据遍历方式
// 正序
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
cout << iter->first << " " << iter->second << endl;
cout << "--------------" << endl;
// 倒序
map<int, string>::reverse_iterator riter;
for(riter = mapStudent.rbegin(); riter != mapStudent.rend(); riter++)
cout << riter->first << " " << riter->second << endl;
cout << "--------------" << endl;
// 数组形式
nSize = mapStudent.size();
for(int nindex = 1; nindex <= nSize; nindex++)
cout<<mapStudent[nindex]<<endl;
}
5、map的查询
第一种:用数组下表,但有一个缺点,如果查询的那个key并不在map中,那么这个Key会被自动加入到Map中,并且,value是默认值
第二种:用find()方法查询(待测试第一种的缺点)
用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器。
查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,
分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.
第三种:用count函数来判定关键字是否出现,其缺点是无法定位数据出现位置,由于map的特性,一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1,出现的情况,当然是返回1了
#include <map>
#include <string>
#include <iostream>
using namespace std;
typedef map<int, string> UDT_MAP_INT_STRING;
typedef map<string, string> UDT_MAP_STR_STRING;
int main()
{
map<int, string> mapStudent;
UDT_MAP_STR_STRING mapStr;
// 三种插入方式
mapStudent[1] = "student_one"; // 可以覆盖
mapStudent.insert(pair<int, string>(2, "student_two")); // 唯一性
mapStudent.insert(map<int, string>::value_type (3, "student_one")); // 唯一性
map<int, string>::iterator iter;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
cout << iter->first << " " << iter->second << endl;
// 1、 数组查询
// 如果查询的键不存在,则会自动插入至Map中
// string 对象判定是否为空的三种方式
string name;
//if ((name = mapStudent[1]).empty())
//if ((name = mapStudent[1]).size() == 0)
if ((name = mapStudent[4]) == "")
cout << "not find " << mapStudent[1] << endl;
else
cout << "find " << mapStudent[1] << endl;
cout << "-------------------" << endl;
for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
cout << iter->first << " " << iter->second << endl;
// 2、 find方法查询
UDT_MAP_INT_STRING::iterator it;
it = mapStudent.find(1);
if (it != mapStudent.end())
cout << "find " << it->first <<":"<< it->second << endl;
mapStr["tom"] = "tomcate";
mapStr.insert(pair<string, string>("kit", "kitty"));
mapStr.insert(UDT_MAP_STR_STRING::value_type ("cob", "cobben"));
// 3、 利用map的 count()函数
string search_world("tom"); // 初始化一个string对象
if ( mapStr.count(search_world))
{
cout << mapStr.find(search_world)->second << endl; // find 返回的是迭代器
cout << mapStr[search_world] << endl; // 数组下标 返回value
}
else
cout << "not found" <<endl;
}
6、map的删除
移除某个map中某个条目用erase()
该成员方法的定义如下:
iterator erase(iterator it);//通过一个条目对象删除
iterator erase(iterator first,iterator last)//删除一个范围
size_type erase(const Key&key);//通过关键字删除
clear()就相当于enumMap.erase(enumMap.begin(),enumMap.end());
这里要用到erase函数,它有三个重载了的函数,下面在例子中详细说明它们的用法
#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"));
//如果你要演示输出效果,请选择以下的一种,你看到的效果会比较好
//如果要删除1,用迭代器删除
map<int, string>::iterator iter;
iter = mapStudent.find(1);
mapStudent.erase(iter);
//如果要删除1,用关键字删除
int n = mapStudent.erase(1);//如果删除了会返回1,否则返回0
//用迭代器,成片的删除
//一下代码把整个map清空
mapStudent.erase( mapStudent.begin(), mapStudent.end() );
//成片删除要注意的是,也是STL的特性,删除区间是一个前闭后开的集合
//自个加上遍历代码,打印输出吧
}
7、map的 swap用法
Map中的swap不是一个容器中的元素交换,而是两个容器交换;
#include <map>
#include <iostream>
using namespace std;
int main( )
{
map <int, int> m1, m2, m3;
map <int, int>::iterator m1_Iter;
m1.insert ( pair <int, int> ( 1, 10 ) );
m1.insert ( pair <int, int> ( 2, 20 ) );
m1.insert ( pair <int, int> ( 3, 30 ) );
m2.insert ( pair <int, int> ( 10, 100 ) );
m2.insert ( pair <int, int> ( 20, 200 ) );
m3.insert ( pair <int, int> ( 30, 300 ) );
cout << "The original map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter->second;
cout << "." << endl;
// This is the member function version of swap
//m2 is said to be the argument map; m1 the target map
m1.swap( m2 );
cout << "After swapping with m2, map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
cout << "After swapping with m2, map m2 is:";
for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
// This is the specialized template version of swap
swap( m1, m3 );
cout << "After swapping with m3, map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
system("pause");
}
8、map 的sort用法
map中的元素是自动按Key升序排序,所以不能对map用sort函数;
这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题的,因为上面的关键字是int 型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数在编译的时候过 不去,下面给出两个方法解决这个问题。
小于号重载:
#include <iostream>
#include <string>
#include <map>
using namespace std;
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; //学生信息
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<<' '<<iter->first.strName<<' '<<iter->second<<endl;
return 0;
}
仿函数的应用,这个时候结构体中没有直接的小于号重载:
#include <iostream>
#include <map>
#include <string>
using namespace std;
typedef struct tagStudentinfo
{
int niD;
string strName;
}Studentinfo, *PStudentinfo; //学生信息
class 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;
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<<' '<<iter->first.strName<<' '<<iter->second<<endl;
}
9、任何一个key值,在map 内最多只会有一份,如果我们需要存储多份相同的key值,就必须使用multimap
#include <map>
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>
struct student{
const char* name;
int age;
};
int main()
{
using namespace std;
student s[]={
{"kitty",23},
{"jack",23},
{"bob",23},
{"mary",23},
{"judice",23}
};
pair<int,student> p1(4,s[0]);
pair<int,student> p2(2,s[1]);
pair<int,student> p3(3,s[2]);
pair<int,student> p4(4,s[3]); //键值key与p1相同
pair<int,student> p5(5,s[4]);
multimap<int,student> mulMap;
mulMap.insert(p1);
mulMap.insert(p2);
mulMap.insert(p3);
mulMap.insert(p4);
mulMap.insert(p5);
cout<<"Init: the total size: "<<mulMap.size()<<endl;
for(multimap<int,student>::iterator iter = mulMap.begin(); iter != mulMap.end(); iter++)
{
cout<<"key: "<<iter->first<<" |value: "<<iter->second.name<<" "<<iter->second.age<<endl;
}
// 二分法查找 key相同的元素范围
typedef multimap<int,student>::iterator mulIterType;
pair<mulIterType,mulIterType> p = mulMap.equal_range(4); //equal_range(key);
//pair<mulIterType,mulIterType> p = equal_range(mulMap.begin(), mulMap.end(), 4); //equal_range(begin(), end(), key, compare); 泛型算法,因为元素是类,因此需要重载operator < 符号,才可以调用
mulIterType iter = mulMap.find(4);
cout<<"found key: "<< iter->first<<" count: "<<mulMap.count(4)<<endl;
for(mulIterType i = p.first; i != p.second; i++)
{
cout<<i->second.name<<" " <<i->second.age<<endl;
}
cout<<"erase the same key element"<<endl;
//mulMap.erase(iter); // 参数为迭代器, 只删除一个元素
mulMap.erase(p.first, p.second); // 参数为迭代器范围,删除所有相同的元素
cout<<"the total size: "<<mulMap.size()<<endl;
for(multimap<int,student>::iterator iter = mulMap.begin(); iter != mulMap.end(); iter++)
{
cout<<"The name: "<<iter->second.name<<" "<<"age: "<<iter->second.age<<endl;