【STL】容器 > 关联式容器 > map

本文深入探讨了STL中的关联容器map,包括其内部基于红黑树的实现,保证插入和删除操作的高效性。map提供了一对一的数据处理能力,允许快速查找、插入和删除。文章介绍了map的构造、插入数据的多种方式(插入pair、value_type,以及通过数组方式),数据遍历、查找、删除和大小判断的方法,并通过实例展示了如何使用map。此外,还提到了map的排序机制和红黑树的特点。
摘要由CSDN通过智能技术生成

map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。map在插入和删除时保证有序(因为基于红黑树实现)。

一、内部实现

map的底层是一棵红黑树,在对节点的插入或是删除操作中,通过旋转来保持平衡性,最坏情况下的插入、删除、查找时间是O(logn),效率非常之高。

1.1 红黑树

1.1.1 特点
1. 节点是红色或黑色。
2. 根节点是黑色。
3 每个叶节点(NIL节点,空节点)是黑色的。
4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点

红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。在C++ STL中,很多部分(包括 set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。
1.1.2 红黑树的应用
C++ STL中的set、map,以及Linux虚拟内存的管理,都是通过红黑树去实现的。

二、使用map

MapSTL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。

下面举例说明什么是一对一的数据映射。比如一个班级中,每个学生的学号跟他的姓名就存在着一一映射的关系,这个模型用map可能轻易描述,很明显学号用int描述,姓名用字符串描述(本篇文章中不用char *来描述字符串,而是采用STLstring来描述),下面给出map描述代码:

Map<int, string> mapStudent;

1.       map的构造函数

map共提供了6个构造函数,这块涉及到内存分配器这些东西,略过不表,在下面我们将接触到一些map的构造方法,这里要说下的就是,我们通常用如下方法构造一个map

Map<int, string> mapStudent;

2.       数据的插入

在构造map容器后,我们就可以往里面插入数据了。这里讲三种插入数据的方法:

第一种:用insert函数插入pair数据,下面举例说明(以下代码虽然是随手写的,应该可以在VCGCC下编译通过,大家可以运行下看什么效果,在VC下请加入这条语句,屏蔽4786警告  pragma warning (disable:4786) )

#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;
}
}


第二种:用insert函数插入value_type数据,下面举例说明

#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”));

上面这两条语句执行后,map1这个关键字对应的值是“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;
}
}


3.       map的大小

在往map里面插入了数据,我们怎么知道当前已经插入了多少数据呢,可以用size函数,用法如下:

Int nSize = mapStudent.size();

4.       数据的遍历

这里也提供三种方法,对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>::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;
}
}


5.       数据的查找(包括判定这个关键字是否在map中出现)

在这里我们将体会,map在数据插入时保证有序的好处。

要判定一个数据(关键字)是否在map中出现的方法比较多,这里标题虽然是数据的查找,在这里将穿插着大量的map基本用法。

这里给出三种数据查找方法

第一种:用count函数来判定关键字是否出现,其缺点是无法定位数据出现位置,由于map的特性,一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1,出现的情况,当然是返回1

第二种:用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于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”));
       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;
}
}


第三种:这个方法用来判定数据是否出现,是显得笨了点,但是,我打算在这里讲解

Lower_bound函数用法,这个函数用来返回要查找关键字的下界(是一个迭代器)

Upper_bound函数用法,这个函数用来返回要查找关键字的上界(是一个迭代器)

例如:map中已经插入了1234的话,如果lower_bound(2)的话,返回的2,而upper-bound2)的话,返回的就是3

Equal_range函数返回一个pairpair里面第一个变量是Lower_bound返回的迭代器,pair里面第二个迭代器是Upper_bound返回的迭代器,如果这两个迭代器相等的话,则说明map中不出现这个关键字,程序说明

#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;
}
}

6.       数据的清空与判空

清空map中的数据可以用clear()函数,判定map中是否有数据可以用empty()函数,它返回true则说明是空map

7.       数据的删除

这里要用到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.earse(mapStudent.begin(), mapStudent.end());
       //成片删除要注意的是,也是STL的特性,删除区间是一个前闭后开的集合
 
       //自个加上遍历代码,打印输出吧
}


8.       其他一些函数用法

这里有swap,key_comp,value_comp,get_allocator等函数,感觉到这些函数在编程用的不是很多,略过不表,有兴趣的话可以自个研究

9.       排序

这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题的,因为上面的关键字是int型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数在编译的时候过不去,下面给出两个方法解决这个问题

第一种:小于号重载,程序举例

#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));
}

10.   另外

由于STL是一个统一的整体,map的很多用法都和STL中其它的东西结合在一起,比如在排序上,这里默认用的是小于号,即less<>,如果要从大到小排序呢,这里涉及到的东西很多,在此无法一一加以说明。

还要说明的是,map中由于它内部有序,由红黑树保证,因此很多函数执行的时间复杂度都是log2N的,如果用map函数可以实现的功能,而STL  Algorithm也可以完成该功能,建议用map自带函数,效率高一些。

下面说下,map在空间上的特性,否则,估计你用起来会有时候表现的比较郁闷,由于map的每个数据对应红黑树上的一个节点,这个节点在不保存你的数据时,是占用16个字节的,一个父节点指针,左右孩子指针,还有一个枚举值(标示红黑的,相当于平衡二叉树中的平衡因子),我想大家应该知道,这些地方很费内存了吧.

使用方法总结

1、map简介

map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。

2、map的功能

  1. 自动建立Key - value的对应。key 和 value可以是任意你需要的类型。
  2. 根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
  3. 快速插入Key - Value 记录。
  4. 快速删除记录
  5. 根据Key 修改value记录。
  6. 遍历所有记录。

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中插入元素

改变map中的条目非常简单,因为map类已经对[]操作符进行了重载

enumMap[1] = "One";

enumMap[2] = "Two";

.....

这样非常直观,但存在一个性能的问题。插入2时,先在enumMap中查找主键为2的项,没发现,然后将一个新的对象插入enumMap,键是2,值是一个空字符串,插入完成后,将字符串赋为"Two"; 该方法会将每个值都赋为缺省值,然后再赋为显示的值,如果元素是类对象,则开销比较大。我们可以用以下方法来避免开销:

enumMap.insert(map<int, CString> :: value_type(2, "Two"))

5、查找并获取map中的元素

下标操作符给出了获得一个值的最简单方法:

CString tmp = enumMap[2];

但是,只有当map中有这个键的实例时才对,否则会自动插入一个实例,值为初始化值。

我们可以使用Find()和Count()方法来发现一个键是否存在。

查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.

int nFindKey = 2; //要查找的Key

//定义一个条目变量(实际是指针)

UDT_MAP_INT_CSTRING::iterator it= enumMap.find(nFindKey);

if(it == enumMap.end()) 

{

//没找到

}

else

{

//找到

}

通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据 iterator->first 和 iterator->second 分别代表关键字和存储的数据

6、从map中删除元素

移除某个map中某个条目用erase()

该成员方法的定义如下

  1. iterator erase(iterator it); //通过一个条目对象删除
  2. iterator erase(iterator first, iterator last); //删除一个范围
  3. size_type erase(const Key& key); //通过关键字删除

clear()就相当于 enumMap.erase(enumMap.begin(), enumMap.end());

C++ STL map的使用

以下是对C++中STL map的插入,查找,遍历及删除的例子:

[cpp]  view plain  copy
 print ?
  1. #include <map>  
  2. #include <string>  
  3. #include <iostream>  
  4. using namespace std;  
  5. void map_insert(map < string, string > *mapStudent, string index, string x)  
  6. {  
  7.     mapStudent->insert(map < string, string >::value_type(index, x));  
  8. }  
  9.   
  10. int main(int argc, char **argv)  
  11. {  
  12.     char tmp[32] = "";  
  13.     map < string, string > mapS;  
  14.   
  15.     //insert element  
  16.     map_insert(&mapS, "192.168.0.128""uestc");  
  17.     map_insert(&mapS, "192.168.200.3""EE");  
  18.     map_insert(&mapS, "192.168.200.33""CS");  
  19.   
  20.     map < string, string >::iterator iter;  
  21.   
  22.     cout << "We Have Third Element:" << endl;  
  23.     cout << "-----------------------------" << endl;  
  24.   
  25.     //find element  
  26.     iter = mapS.find("192.168.0.33");  
  27.     if (iter != mapS.end())  
  28.     {  
  29.         cout << "find the elememt" << endl;  
  30.         cout << "It is:" << iter->second << endl;  
  31.     }  
  32.     else  
  33.     {  
  34.         cout << "not find the element" << endl;  
  35.     }  
  36.   
  37.     //see element  
  38.     for (iter = mapS.begin(); iter != mapS.end(); iter++ )  
  39.     {  
  40.   
  41.         cout << "| " << iter->first << " | " << iter->  
  42.         second << " |" << endl;  
  43.   
  44.     }  
  45.     cout << "-----------------------------" << endl;  
  46.   
  47.     map_insert(&mapS, "192.168.30.23""CT");  
  48.   
  49.     cout << "After We Insert One Element:" << endl;  
  50.     cout << "-----------------------------" << endl;  
  51.     for (iter = mapS.begin(); iter != mapS.end(); iter++ )  
  52.     {  
  53.   
  54.         cout << "| " << iter->first << " | " << iter->  
  55.         second << " |" << endl;  
  56.   
  57.     }  
  58.   
  59.     cout << "-----------------------------" << endl;  
  60.   
  61.     //delete element  
  62.     iter = mapS.find("192.168.200.33");  
  63.     if (iter != mapS.end())  
  64.     {  
  65.         cout << "find the element:" << iter->first << endl;  
  66.         cout << "delete element:" << iter->first << endl;  
  67.         cout << "=================================" << endl;  
  68.         mapS.erase(iter);  
  69.     }  
  70.     else  
  71.     {  
  72.         cout << "not find the element" << endl;  
  73.     }  
  74.     for (iter = mapS.begin(); iter != mapS.end(); iter++ )  
  75.     {  
  76.   
  77.         cout << "| " << iter->first << " | " << iter->  
  78.         second << " |" << endl;  
  79.   
  80.     }  
  81.     cout << "=================================" << endl;  
  82.   
  83.     return 0;  
  84. }  
  85. /*************** 
  86. We Have Third Element: 
  87. ----------------------------- 
  88. not find the element 
  89. | 192.168.0.128 | uestc | 
  90. | 192.168.200.3 | EE | 
  91. | 192.168.200.33 | CS | 
  92. ----------------------------- 
  93. After We Insert One Element: 
  94. ----------------------------- 
  95. | 192.168.0.128 | uestc | 
  96. | 192.168.200.3 | EE | 
  97. | 192.168.200.33 | CS | 
  98. | 192.168.30.23 | CT | 
  99. ----------------------------- 
  100. find the element:192.168.200.33 
  101. delete element:192.168.200.33 
  102. ================================= 
  103. | 192.168.0.128 | uestc | 
  104. | 192.168.200.3 | EE | 
  105. | 192.168.30.23 | CT | 
  106. ================================= 
  107.  
  108. Process returned 0 (0x0)   execution time : 1.080 s 
  109. Press any key to continue. 
  110.  
  111. *****************/  

Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。

下面举例说明什么是一对一的数据映射。比如一个班级中,每个学生的学号跟他的姓名就存在着一一映射的关系,这个模型用map可能轻易描述,很明显学号用int描述,姓名用字符串描述(本篇文章中不用char *来描述字符串,而是采用STL中string来描述),下面给出map描述代码:

Map<int, string> mapStudent;

1.       map的构造函数

map共提供了6个构造函数,通常用如下方法构造一个map:

Map<int, string> mapStudent;

2.       数据的插入

在构造map容器后,我们就可以往里面插入数据了。这里讲三种插入数据的方法:

第一种:用insert函数插入pair数据,下面举例说明 

 
[cpp]  view plain  copy
 print ?
  1. #include <string>  
  2. #include <iostream>  
  3. #include <map>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.         map<int, string> mapStudent;  
  8.         mapStudent.insert(pair<int, string>(1, "student_one"));  
  9.         mapStudent.insert(pair<int, string>(2, "student_two"));  
  10.         mapStudent.insert(pair<int, string>(3, "student_three"));  
  11.         map<int, string>::iterator  iter;  
  12.   
  13.         for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  14.         {  
  15.             cout<<iter->first<<"   "<<iter->second<<endl;  
  16.         }  
  17. }  
  18. /******************** 
  19. 1   student_one 
  20. 2   student_two 
  21. 3   student_three 
  22.  
  23. Process returned 0 (0x0)   execution time : 0.783 s 
  24. Press any key to continue. 
  25.  
  26. *********************/  

第二种:用insert函数插入value_type数据,下面举例说明

 
[cpp]  view plain  copy
 print ?
  1. #include <string>  
  2. #include <iostream>  
  3. #include <map>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.         map<int, string> mapStudent;  
  8.         mapStudent.insert(map<int, string>::value_type (1, "student_one"));  
  9.         mapStudent.insert(map<int, string>::value_type (2, "student_two"));  
  10.         mapStudent.insert(map<int, string>::value_type (3, "student_three"));  
  11.         map<int, string>::iterator  iter;  
  12.         for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  13.         {  
  14.             cout<<iter->first<<"   "<<iter->second<<endl;  
  15.         }  
  16. }  
  17. /******************** 
  18. 1   student_one 
  19. 2   student_two 
  20. 3   student_three 
  21.  
  22. Process returned 0 (0x0)   execution time : 0.783 s 
  23. Press any key to continue. 
  24.  
  25. *********************/  

第三种:用数组方式插入数据,下面举例说明

 
[cpp]  view plain  copy
 print ?
  1. #include <string>  
  2. #include <iostream>  
  3. #include <map>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.         map<int, string> mapStudent;  
  8.         mapStudent[1] =  "student_one";  
  9.         mapStudent[2] =  "student_two";  
  10.         mapStudent[3] =  "student_three";  
  11.         map<int, string>::iterator  iter;  
  12.         for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  13.         {  
  14.             cout<<iter->first<<"   "<<iter->second<<endl;  
  15.         }  
  16. }  
  17. /******************** 
  18. 1   student_one 
  19. 2   student_two 
  20. 3   student_three 
  21.  
  22. Process returned 0 (0x0)   execution time : 0.783 s 
  23. Press any key to continue. 
  24.  
  25. *********************/  

以上三种用法,虽然都可以实现数据的插入,但是它们是有区别的,当然了第一种和第二种在效果上是完成一样的,用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。

下面给出完成代码,演示插入成功与否问题

 
[cpp]  view plain  copy
 print ?
  1. #include <map>  
  2. #include <string>  
  3. #include <iostream>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.     map<int, string> mapStudent;  
  8.     pair<map<int, string>::iterator, bool> Insert_Pair;  
  9.     mapStudent.insert(pair<int, string>(1, "student_one"));  
  10.     mapStudent.insert(pair<int, string>(2, "student_two"));  
  11.     mapStudent.insert(pair<int, string>(3, "student_three"));  
  12.     /************************************ 
  13.     mapStudent[1] =  "student_one"; 
  14.     mapStudent[2] =  "student_two"; 
  15.     mapStudent[3] =  "student_three"; 
  16.     Insert_Pair = mapStudent.insert(pair<int, string>(1, "student_insert")); 
  17.     这种写法运行结果: 
  18.     1   student_one 
  19.     2   student_two 
  20.     3   student_three 
  21.     Insert Failure 
  22.     Insert Failure 
  23.     1   student_one 
  24.     2   student_two 
  25.     3   student_three 
  26.  
  27.  
  28.     ****************************************/  
  29.   
  30.     map<int, string>::iterator  iter;  
  31.     for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  32.     {  
  33.         cout<<iter->first<<"   "<<iter->second<<endl;  
  34.     }  
  35.     Insert_Pair = mapStudent.insert(pair<int, string>(6, "student_insert"));  
  36.     if(Insert_Pair.second == true)  
  37.     {  
  38.         cout<<"Insert Successfully"<<endl;  
  39.     }  
  40.     else  
  41.     {  
  42.     cout<<"Insert Failure"<<endl;  
  43.     }  
  44.     Insert_Pair =mapStudent.insert(pair<int, string>(1, "student_two"));  
  45.     if(Insert_Pair.second == true)  
  46.     {  
  47.         cout<<"Insert Successfully"<<endl;  
  48.     }  
  49.     else  
  50.     {  
  51.         cout<<"Insert Failure"<<endl;  
  52.     }  
  53.   
  54.     for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  55.     {  
  56.         cout<<iter->first<<"   "<<iter->second<<endl;  
  57.     }  
  58. }  
  59. /************************************ 
  60. 1   student_one 
  61. 2   student_two 
  62. 3   student_three 
  63. Insert Successfully 
  64. Insert Failure 
  65. 1   student_one 
  66. 2   student_two 
  67. 3   student_three 
  68. 6   student_insert 
  69.  
  70. Process returned 0 (0x0)   execution time : 0.835 s 
  71. Press any key to continue. 
  72.  
  73. *************************************/  

大家可以用如下程序,看下用数组插入在数据覆盖上的效果

[cpp]  view plain  copy
 print ?
  1. #include <map>  
  2. #include <string>  
  3. #include <iostream>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.     map<int, string> mapStudent;  
  8.     mapStudent[1] =  "student_one";  
  9.     mapStudent[1] =  "student_two";  
  10.     mapStudent[2] =  "student_three";  
  11.     map<int, string>::iterator  iter;  
  12.     for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  13.     {  
  14.         cout<<iter->first<<"   "<<iter->second<<endl;  
  15.     }  
  16. }  
  17. /******************************** 
  18. 1   student_two 
  19. 2   student_three 
  20.  
  21. Process returned 0 (0x0)   execution time : 0.888 s 
  22. Press any key to continue. 
  23.  
  24. *********************************/  

 

3.       map的大小

在往map里面插入了数据,我们怎么知道当前已经插入了多少数据呢,可以用size函数,用法如下:

Int nSize = mapStudent.size();

4 、 数据的查找(包括判定这个关键字是否在map中出现)

在这里我们将体会,map在数据插入时保证有序的好处。

要判定一个数据(关键字)是否在map中出现的方法比较多,这里标题虽然是数据的查找,在这里将穿插着大量的map基本用法。

这里给出三种数据查找方法

第一种:用count函数来判定关键字是否出现,其缺点是无法定位数据出现位置,由于map的特性,一对一的映射关系,就决定了count函数的返回值只有两个,要么是0,要么是1,出现的情况,当然是返回1了

第二种:用find函数来定位数据出现位置,它返回的一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器。

 
[cpp]  view plain  copy
 print ?
  1. #include <map>  
  2. #include <string>  
  3. #include <iostream>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.     map<int, string> mapStudent;  
  8.     mapStudent.insert(pair<int, string>(1, "student_one"));  
  9.     mapStudent.insert(pair<int, string>(2, "student_two"));  
  10.     mapStudent.insert(pair<int, string>(3, "student_three"));  
  11.     map<int, string>::iterator iter;  
  12.     iter = mapStudent.find(1);  
  13.     if(iter != mapStudent.end())  
  14.     {  
  15.         cout<<"Find, the value is "<<iter->second<<endl;  
  16.     }  
  17.     else  
  18.     {  
  19.         cout<<"Do not Find"<<endl;  
  20.     }  
  21.     iter = mapStudent.find(6);  
  22.     if(iter != mapStudent.end())  
  23.     {  
  24.         cout<<"Find, the value is "<<iter->second<<endl;  
  25.     }  
  26.     else  
  27.     {  
  28.         cout<<"Do not Find"<<endl;  
  29.     }  
  30. }  
  31. /*********************************** 
  32. Find, the value is student_one 
  33. Do not Find 
  34.  
  35. Process returned 0 (0x0)   execution time : 1.030 s 
  36. Press any key to continue. 
  37.  
  38. *************************************/  

5、     数据的清空与判空

清空map中的数据可以用clear()函数,判定map中是否有数据可以用empty()函数,它返回true则说明是空map

6.       数据的删除

这里要用到erase函数,它有三个重载了的函数,下面在例子中详细说明它们的用法

[cpp]  view plain  copy
 print ?
  1. #include <map>  
  2. #include <string>  
  3. #include <iostream>  
  4. using namespace std;  
  5. int main()  
  6. {  
  7.     map<int, string> mapStudent;  
  8.     mapStudent.insert(pair<int, string>(1, "student_one"));  
  9.     mapStudent.insert(pair<int, string>(2, "student_two"));  
  10.     mapStudent.insert(pair<int, string>(3, "student_three"));  
  11.   
  12.   
  13.     map<int, string>::iterator iter;  
  14.     cout<<"--------------------no erase--------------------"<<endl;  
  15.      for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  16.     {  
  17.         cout<<iter->first<<"   "<<iter->second<<endl;  
  18.     }  
  19.     cout<<"-------------erase (iter)--------iter = mapStudent.find(1)--"<<endl;  
  20.     iter = mapStudent.find(1);  
  21.     mapStudent.erase(iter);  
  22.     //如果要删除1,用关键字删除  
  23.   
  24.     for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  25.     {  
  26.         cout<<iter->first<<"   "<<iter->second<<endl;  
  27.     }  
  28.      cout<<"-------------int n = mapStudent.erase(2)----"<<endl;  
  29.     int n = mapStudent.erase(2);//如果删除了会返回1,否则返回0  
  30.       for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  31.     {  
  32.         cout<<iter->first<<"   "<<iter->second<<endl;  
  33.     }  
  34.      cout<<"---  mapStudent.erase(mapStudent.begin(), mapStudent.end())-----"<<endl;  
  35.     //一下代码把整个map清空  
  36.     mapStudent.erase(mapStudent.begin(), mapStudent.end());  
  37.     for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)  
  38.     {  
  39.         cout<<iter->first<<"   "<<iter->second<<endl;  
  40.     }  
  41.   
  42. }  
  43. /************************** 
  44. --------------------no erase-------------------- 
  45. 1   student_one 
  46. 2   student_two 
  47. 3   student_three 
  48. -------------erase (iter)--------iter = mapStudent.find(1)-- 
  49. 2   student_two 
  50. 3   student_three 
  51. -------------int n = mapStudent.erase(2)---- 
  52. 3   student_three 
  53. ---  mapStudent.erase(mapStudent.begin(), mapStudent.end())----- 
  54.  
  55. Process returned 0 (0x0)   execution time : 1.513 s 
  56. Press any key to continue. 
  57.  
  58. ****************************/ 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值