[转] STL中map用法详解

一.Map概述 

        Map
STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。这里说下map内部数据的组织,map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。
下面举例说明什么是一对一的数据映射。比如一个班级中,每个学生的学号跟他的姓名就存在着一一映射的关系,这个模型用map可能轻易描述,很明显学号用int描述,姓名用字符串描述(本篇文章中不用char *来描述字符串,而是采用STLstring来描述),下面给出map描述代码:
Map<int, string> mapStudent;     

二.
数据的插入 

        在构造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(map<int, string>::value_type (1, "student_one"));
       If(Insert_Pair.second == true)
       {
              Cout<<”Insert Successfully”<<endl;
       }
       Else
       {
              Cout<<”Insert Failure”<<endl;
       }
       Insert_Pair = mapStudent.insert(map<int, string>::value_type (1, "student_one"));
       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; 
      }
}    

三. map
的构造函数 

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

四.   map
的大小 
      在往map里面插入了数据,我们怎么知道当前已经插入了多少数据呢,可以用size函数,用法如下:
Int nSize = mapStudent.size();

五. 
数据的遍历 
      这里也提供三种方法,对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 = 0; nIndex < nSize; nIndex++) 
      { 
           Cout<<mapStudent[nIndex]<<end; 
      }
}

六.  数据的查找(包括判定这个关键字是否在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; 
     }
}

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

八. 数据的删除 
        这里要用到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的特性,删除区间是一个前闭后开的集合

       //自个加上遍历代码,打印输出吧
}

九. 其他一些函数用法 

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

十. 排序 

      这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题
的,因为上面的关键字是int型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问
题,因为它没有小于号操作,insert等函数在编译的时候过不去,下面给出两个方法解决这个问题
第一种:小于号重载,程序举例
#include <map>
#include <string>
Using namespace std;
Typedef struct tagStudentInfo
{
       Int      nID;
       String   strName;
}StudentInfo, *PStudentInfo;  //学生信息

Int main()
{
       //用学生信息映射分数
       Map<StudentInfo, int>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));
}
以上程序是无法编译通过的,只要重载小于号,就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));
}     

转载于:https://www.cnblogs.com/ForEverKissing/archive/2008/05/06/1184705.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HDU 1874 畅通工程续

畅通工程续 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 9566 Accepted Submission(s): 3200 Problem Description某省自从实行了很多年的畅通工程计划后&#xff0c;终于修建了很多路。不过路多了也不好&am…

转换流

一、编码和解码 二、编码带来的问题 三、转换流InputStreamReader和OutputStreamWriter编码和解码的原理 看懂的字符变成看不懂的字节编码 和 把看不懂的字节编码变成看懂的字符&#xff1b; 字节和字符转换的桥梁&#xff0c;不写默认utf-8&#xff08;国际规定&#xff09;&a…

序列化流

一、对象的序列化和反系列化 二、对象的序列化流ObjectOutputStream 标记型接口&#xff1a; 使用序列化流ObjectOutputStream将对象写入到文件中进行序列化&#xff1a; 执行过后的文件&#xff1a; 二进制字节存储&#xff0c;无法直接查看&#xff1b; 三、对象的反序列化流…

Asp.Net中虚拟文件系统的使用

具体实现步骤如下&#xff1a;一、开发web用户控件这一步和以前的开发没有区别。1、首先新建一个web应用程序(需要VS2005 sp1支持)2、然后在里面开发几个web用户控件3、在ascx文件上右键-〉属性-〉生成操作选择嵌入的资源4、生成dll就可以了(dll的名字为&#xff1a;Test.Contr…

打印流

一、打印流输出数据到文件 全路径&#xff0c;没有操作系统没有E盘&#xff0c;异常&#xff1b; 二、打印流修改打印输出路径 会生成一个记录的文件&#xff1a; 可用来记录一些操作日志&#xff1b; 转载于:https://www.cnblogs.com/wmqiang/p/11374696.html

乘法表

&#xfeff;&#xfeff;叙述性说明 法表或许将会扎根于我们一生的记忆,如今让我们重温那些温暖的记忆,请编程输出九九乘法表. 如今要求你输出它的格式与寻常的 不同啊! 是那种反过来的三角形啦&#xff0c;详细例如以下图&#xff1a; 每两个式子之前用一个空格 隔开。。。 输…

DropDownList实现无限级分类

要想实现无限级分类&#xff0c;那得还用传统的老方法----递归&#xff0c;也许有很多人会抱怨递归的性能不是太理想。俗话说的话&#xff0c;能抓到老鼠的猫就是好猫。我提倡先解决问题&#xff0c;然后再优化性能。 数据库结构&#xff1a; 代码&#xff1a; protectedvoidGe…

50张非常精美的Apple主题桌面壁纸(上篇)

今天这篇文章向大家分享50张非常精美的Apple主题桌面壁纸&#xff0c;果粉们赶紧来下载啊。 Blue Apple wallpaper Apple Lawn .wallpaper. by ~VertigoStudio A quite simple Wallpaper, without mutch falderal Green Apple PSP by ~ARVQ Mac Apple Wallpapers With Android …

[文摘]上软解散相关

真实系列文摘 之 上海软星仙剑开发组解散真正内幕-----附.上软人最后留给玩家的话我不是个疯狂的仙剑迷, 但我有朋友是; 我不是个对看不管惯的社会现象能挺身而出的人, 但还是喜欢去在意去关心那些事...下面这个算不上是什么新闻了, 但如过是玩过仙剑系列觉得还不错的人, 对游戏…

Apache Spark 1.5发布,新特性一览

Apache Spark是一个围绕速度、易用性和复杂分析构建的大数据处理框架。最初在2009年由加州大学伯克利分校的AMPLab开发&#xff0c;并于2010年成为Apache的开源项目之一。Apache Spark社区刚刚发布了1.5版本&#xff0c;明略数据高级工程师梁堰波解析了该版本中的众多新特性&am…

开源软件

邮件服务器&#xff1a; Postfixftp服务器&#xff1a; vsftpd统计&#xff1a; nginx access log awstats 统计&#xff1a; google统计 google分析 腾讯分析 分布式锁及配置管理&#xff1a;Zookeeper php框架&#xff1a;thinkphp运维监控&#xff1a; cacti数据同步&#…

cad.net 获取所有已经安装的cad版本信息

计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\Hardcopy 转载于:https://www.cnblogs.com/JJBox/p/11381254.html

Restangular的使用

2019独角兽企业重金招聘Python工程师标准>>> // First way of creating a Restangular object. Just saying the base URL var baseAccounts Restangular.all(accounts); // This will query /accounts and return a promise. baseAccounts.getList().then(functio…

SQL Server的镜像是基于物理块变化的复制 镜像Failover之后数据的预热问题

SQL Server的镜像是基于物理块变化的复制 镜像Failover之后数据的预热问题 基于物理块变化的复制&#xff0c;没有并行也是很快的。 逻辑复制的日志是按事务结束的时间排序的&#xff0c;而物理复制是与事务无关的&#xff0c;只要发生了改变&#xff0c;就可以立即传送到备库&…

mybatis学习教程中级(十)mybatis和ehcache缓存框架整合(重点)

1、前言 前面讲解了mybatis的一级、二级缓存。一级然并卵&#xff08;spring整合后&#xff09;&#xff0c;二级还是有用的。我们现在来看看用ehcache来维护管理二级缓存。不要问我为什么&#xff0c;因为都这么用&#xff01;&#xff01;&#xff01;java是框架语言&#x…

如何使用三态工作流 - [MOSS 2007应用日记]

MOSS 2007的一个很重要的功能就是提供了工作流&#xff0c;让我们可以结合工作流来实现各种需求&#xff0c;系统提供了几种默认的工作流供大家使用&#xff0c;“三态工作流”就是默认的一种。 现在通过一个模拟实验来看看怎么使用“三态工作流”&#xff1a;在行政部子网站下…

Linux下samba服务的错误处理

错误显示:解决方法:在/etc/samba/smb.conf 文件里有一行自己修改过hosts allow 192.168.x.x x.x.x.x在这里加上自己的充当客户端主机的ip地址即可转载于:https://blog.51cto.com/luochen2015/1693712

[POJ2420 A Star not a Tree?]

[关键字]&#xff1a;随机化搜索 模拟退火 [题目大意]&#xff1a;给出n个点&#xff0c;找出一个距离所有点之和最小的点&#xff0c;输出距离。 // [分析]&#xff1a;同样是随机化的方法&#xff0c;只是在把没个点随机移动时有小小的变动。poj1379是使用得随机一个角度x然后…

使用file做swap分区

有时候在给系统盘分区时&#xff0c;忘记swap分区&#xff0c;这种情况下&#xff0c;可以用一个文件做swap&#xff0c;效果差不多的。这里就以2Gswap分区为例。步骤&#xff1a;1、创建2G大小的文件dd if/dev/zero of/swap bs1M count20482、格式化swap filemkswap /swap3、把…

react和vue配置本地代理

React 在react中配置开发环境下的本地代理相对比较简单&#xff0c;直接在package.json文件中修改即可。 但是这样做有其局限性&#xff0c;如果开发中代理多个接口的时候将无法满足需求&#xff0c;我们需要的是下面这种的能够代理多个接口的请求方式 proxy(/back, {target: h…