STL | Map(映射)的使用

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

一. 定义一个Map(映射)

map共提供了6个构造函数,介绍最常见的一种构造方法:

#include<map>// 头文件
map<char,int>Map;// 定义一个从char类型到int类型的映射Map

构造函数包含了两个参数,第一个参数是关键字Key,第二个参数是关键字的值Key_Value。这两个参数可以是任意类型。

通常,我们习惯用typedef来定义Map,为什么呢?因为在定义迭代器的时候,我们可以不用多写多余的重复代码,而且要修改Map的时候,也不需要修改多处地方。

#include<map>
typedef map<char,int> m;// 自定义一种类型——m
m Map;

二. 插入数据

定义好了映射Map,接下来就需要向Map插入数据。插入数据主要有以下三种方法。

① 用insert函数插入pair数据(pair是什么,其实就是一个结构体,包含(first,second)这样的数据的结构体));

char ch = “a”;
int i = 10;
Map.insert(pair<char,int>(ch,i));

② 用insert函数插入value_type数据;

Map.insert(m::value_type(ch,i));

③ 用数组方式插入数据:形式如:Map[Key]=Key_Value;

 Map[ch]=i;

以上三种插入方法,虽然都可以实现数据的插入,但是它们是有区别的。当然,第一种和第二种在效果上是完成一样的。

insert函数插入数据,在数据的插入上涉及到集合的唯一性这个概念,即当map中有这个关键字时,想要再次插入该关键字,insert操作是插入不了的。

但是用数组方式就不同了,它可以覆盖以前该关键字对应的值。

三. Map容器的大小

Map容器已经插入了数据,那么Map容器的大小(目前)是多大呢?或者说插入了多少组数据呢?

Map容器已经插入了数据,那么Map容器的大小(目前)是多大呢?或者说插入了多少组数据呢?

四. 遍历Map容器

既然插入了数据,那么我们怎么去遍历呢?(借此也看看是不是插入成功)同样的,也有三种方法可以对Map容器进行遍历。

① 前向迭代器遍历

map<char,int>::iterator iter;// 前向迭代器 
for(iter=Map.begin();iter!=Map.end();iter++)
{
    cout<<iter->first<<" "<<iter->second<<endl;
}

② 反向迭代器遍历:所谓反向,就是从末尾开始遍历。

map<char,int>::iterator iter;// 前向迭代器 
for(iter=Map.begin();iter!=Map.end();iter++)
{
    cout<<iter->first<<" "<<iter->second<<endl;
}

③ 数组的形式遍历

#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++)  
	//而不是 for(int nindex = 0; nindex < nSize; nindex++)        
	for(int nindex = 1; nindex <= nSize; nindex++)            
		cout<<mapStudent[nindex]<<endl;    

}  

五.判定关键字是否在Map中的方法

这里有三种判断关键字是否在Map中的方法。

① 用count()函数:
由于Map的特性,一对一的映射关系(且无重复元素),决定了count函数的返回值只有两个,要么是0,要么是1。若关键字在Map中,count函数返回1;不在则返回0。
使用形式:count(Key)

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

map<char,int>Map;
map<char,int>::iterator iter=Map.find(Key);
if(iter==Map.end())cout<<"can't find"<<endl;
else cout<<"find"<<endl;

③ 用lower_bound()函数upper_bound()函数或者equal_value()函数:(虽然方法显示笨重了些,但是体现了Map数据的有序性)
ower_bound():返回键值给定元素的第一个位置(下界)

upper_bound():返回键值给定元素的第一个位置(上界)

equal_range():返回特殊条目的迭代器对。具体表现为:

返回一个pair,pair里面第一个变量是lower_bound返回的迭代器,pair里面第二个迭代器是upper_bound返回的迭代器。

如果这两个迭代器(上、下界)相等的话,则说明Map中不存在这个关键字。

if(iter_1!=iter_2)cout<<"find"<<endl;
else cout<<"can't find"<<endl;

完整代码,测试lower_bound、upper_bound、equal_value函数 :

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;

typedef map<char,int>m;
m Map;

int main()
{
    char ch;
    for(int i=0;i<5;i++)
    {
        cout<<"input character:";
        cin>>ch;
        Map[ch]=i;
    }
    m::iterator iter_1,iter_2;
    iter_1=Map.lower_bound('C');
    iter_2=Map.upper_bound('C');
    cout<<"lower_bound:\n";
    cout<<iter_1->first<<"->"<<iter_1->second<<endl;
    cout<<"upper_bound:\n";
    cout<<iter_2->first<<"->"<<iter_2->second<<endl;
    cout<<"*********************\n";
    cout<<"queal_value:\n";
    pair<m::iterator,m::iterator> p=Map.equal_range('C');
    iter_1=p.first;
    iter_2=p.second;
    cout<<iter_1->first<<"->"<<iter_1->second<<endl;
    cout<<iter_2->first<<"->"<<iter_2->second<<endl;
} 

在这里插入图片描述

查找关键字:
find函数
返回一个pair对象,pair->first表示Key的值,pair->second表示Key_Value的值。

result = Map.find(Key);
cout << result->first << "->" << result->second << endl;

六.Map的基本操作函数

*begin():返回指向Map头部的迭代器
*clear():删除所有元素
*count():返回指定元素出现的次数,Map中只有01两个值
*empty():如果Map为空,则返回true
*end():返回指向Map末尾的迭代器
equal_range():返回特殊条目的迭代器对
*erase():删除一个元素
*find():查找一个元素*
insert():插入元素
*rbegin():返回一个指向Map尾部的反向迭代器
*rend():返回一个指向Map头部的反向迭代器
*size():返回map中元素的个数
*swap():交换两个Map容器
equal_range():返回特殊条目的迭代器对
lower_bound():返回键值>=给定元素的第一个位置
upper_bound():返回键值>给定元素的第一个位置
value_comp():返回比较元素Key_Value的函数
max_size():返回可以容纳的最大元素个数
key_comp():返回比较元素Key的函数

七.对Map进行排序

①自然数值key的排序

Map是有序的,自动按照Key进行升序排序(STL中默认是采用小于号来排序的)。下面我们通过前面的一段代码来验证Map的有序性。

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;

typedef map<char,int>m;
m Map;

int main()
{
    char ch;
    for(int i=0;i<5;i++)
    {
        cout<<"input character:";
        cin>>ch;
        //Map.insert(m::value_type(ch,i));
        //Map.insert(pair<char,int>(ch,i));
        Map[ch]=i;
    }
    // 前向迭代器遍历 
    map<char,int>::iterator iter;// 前向迭代器 
    for(iter=Map.begin();iter!=Map.end();iter++)
    {
        cout<<iter->first<<" "<<iter->second<<endl;
    }   
} 

在这里插入图片描述

既然是按照小于号来排序的,那么,如果插入的Key的类型是类或者结构体,因为结构体不支持小于号运算,所以当涉及到排序操作时就会出现问题。

如何解决非数值类型的排序比较呢?主要有下面两种方法。

②非数值类型的key排序

重载小于号

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;

typedef struct Student
{
    int age;
    int score;
    // 重载小于号 
    bool operator <(Student const& temp)const
    {
        if(age<temp.age)return true;
        else if(age==temp.age)
        {
            if(score<temp.score)return true;
            else return false;
        }
        else if(age>temp.age)return false;
    } 
}Student;
vector<Student>students;
typedef map<Student,int> m;
m Map;

int main()
{
    int n;
    cout<<"input the total numberof students:";
    cin>>n;
    Student temp;
    for(int i=0;i<n;i++)
    {
        cout<<"input the age and score of student:";
        cin>>temp.age>>temp.score;
        Map[temp]=i;
        students.push_back(temp);
    } 
    m::iterator iter;
    for(iter=Map.begin();iter!=Map.end();iter++)
    {
        cout<<iter->first.age<<" "<<iter->first.score<<endl;
    }
} 

仿函数的应用

(这个时候结构体中没有直接的小于号重载)

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;

typedef struct Student
{
    int age;
    int score;
}Student;
vector<Student>students;
// 仿函数 
class sort
{
    public:
        bool operator()(Student const &A,Student const &B)
        {
            if(A.age<B.age)return true;
            else if(A.age==B.age)
            {
                if(A.score<B.score)return true;
                else return false;
            }
            else if(A.age>B.age)return false;
        }   
};
typedef map<Student,int,sort> m;
m Map;

int main()
{
    int n;
    cout<<"input the total numberof students:";
    cin>>n;
    Student temp;
    for(int i=0;i<n;i++)
    {
        cout<<"input the age and score of student:";
        cin>>temp.age>>temp.score;
        Map[temp]=i;
        students.push_back(temp);
    } 
    m::iterator iter;
    for(iter=Map.begin();iter!=Map.end();iter++)
    {
        cout<<iter->first.age<<" "<<iter->first.score<<endl;
    }
} 

八.Map的删除

当使用完了Map容器后,我们可以将 容器清空或者删除处理,以腾出空闲的空间来。接下来看一下Map容器的删除函数。

earse()函数:删除Map中的条目(一个或多个)

该成员方法的定义如下:
iterator erase(iterator it);// 通过一个条目对象删除
iterator erase(iterator first,iterator last)// 删除一个范围
size_type erase(const Key&key);// 通过关键字删除

clear()函数:直接将整个Map删除

相当于erase(Map.begin(),Map.end())

另外有关于Map容器的嵌套使用和嵌套删除,有些固定的使用方法,比如删除嵌套Map容器的元素,需要遍历一个一个erase,具体参见博客;

参考:
https://www.jianshu.com/u/d9e886863e82
https://www.cnblogs.com/pualus/p/9319091.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值