【map存储自定义类型】

map

类模板原型

map是一个类模板,实例化时需要提供以下的模板实参。

 template <typename _Key, 
 		   typename _Tp,
 		   typename _Compare = std::less<_Key>,
	       typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
    class map
    {
    	...
    }

_Key :键的类型,无默认值,是必需的
_Tp :值的类型,无默认值,是必需的
**_Compare ** :比较(仿)函数,有默认值。当键_Key是int、double、bool等内置类型时,将调用stl_function.h中预定义的std::less类模板;当键_Key是自定义类型,需要传入自定义类型的比较函数。
_Alloc :空间分配器,有默认值,进行空间的分配与回收,一般使用默认。

模板实参

使用unordered_set存储自定义类型的键时,至少需要提供3个模板实参:

  • 存储的自定义的键类型_Value
  • 值的类型_Tp
  • 比较函数_Compare

源代码

错误示例

#include <iostream>
#include <map>

using namespace std;

struct MyPair{
    int x_;
    int y_;

    MyPair(int x, int y):x_(x),y_(y){
    }

    bool operator<(const MyPair &larger) const{
        return y_ <= larger.y_;                 //这里错误地使用 <=
    }
};
 
int main(){
    map<MyPair,                                //typename _Key
        int>                                   //typename _Tp
        umap;                                           
                                               
    umap[MyPair(1,1)] = 1;
    umap[MyPair(1,1)] = 1;
    umap[MyPair(2,2)] = 2;
    umap.emplace(MyPair(2,2),2);
        
    for(const auto &it: umap)
        cout << it.first.x_ <<","<< it.first.y_ << "," << it.second << endl;
}

错误示例的控制台结果

1,1,1
1,1,1
2,2,2
2,2,2

可以看到map中的元素重复了,这是因为提供的比较函数不满足严格弱排序。比较(仿)函数Comp可以视作二元关系R,需要满足以下3个特点:

  • 反自反关系:R是A上的反自反关系⇔∀a∈A→¬(aRa)),即Comp(x,x)的返回值为false;
  • 反对称关系:R是A上的反对称关系⇔∀a,b∈A, aRb ^ bRa → a=b,即Comp(a,b)与Comp(b,a)的返回值同为false时(或者同为true时),a=b;
  • 传递性:对∀a,b∈A,c∈A,当aRb,bRc时,有aRc,即Comp(a,b)与Comp(b,c)的返回值同为true时,Comp(a,c)的返回值也为true;
    Comp(a,b)与Comp(b,c)的返回值同为false时,Comp(a,c)的返回值也为false;

从上面可以看出,小于运算符是满足以上三个条件的;而小于等于运算符满足反对称关系和传递性,但是不满足反自反关系。所以在MyPair的小于运算符函数体中,应该使用满足严格弱排序的小于运算符(或者大于运算符)。

正确示例

常见的做法有两种,一种是提供比较函数;另一种是在自定义类型中重载小于运算符(也是函数的一种),这两种方法都需要函数满足严格弱排序

#include <iostream>
#include <map>

using namespace std;

struct MyPair{
    int x_;
    int y_;

    MyPair(int x, int y):x_(x),y_(y){
    }

    // //第一种方法,自定义键中重载小于运算符,切记严格弱排序,函数参数与成员函数均为const
    // bool operator<(const MyPair &larger) const{
    //     return y_ > larger.y_;                 
    // }
};

//第二种方法,提供比较仿函数,map的类模板实参配合map的构造函数有多种写法,文章【unordered_set存储自定义类型】中已经列举过,不再重复
struct Comp{
    bool operator()(const MyPair& smaller, const MyPair& larger)const{
        return smaller.y_  < larger.y_;
    }
};

int main(){
    map<MyPair,                                //typename _Key
        int,                                   //typename _Tp
        Comp>                                  //typename _Compare
        umap;                                           
                                               
    umap[MyPair(1,1)] = 1;
    umap[MyPair(1,1)] = 1;
    umap[MyPair(2,2)] = 2;
    umap.emplace(MyPair(2,2),2);			  //emplace原地构造
    
    for(const auto &it: umap)
        cout << it.first.x_ <<","<< it.first.y_ << "," << it.second << endl;
}

控制台结果

1,1,1
2,2,2

结论:

  1. 在理解unordered_set和map的类模板后,遇到没有提及的unordered_map、set、priority_queue、pair也可以通过查看其类模板和构造函数,来了解应该提供的模板实参和构造函数需要的参数,所以第二种方法的三种形式也不再赘述;
  2. 在遇到模板实参是 std::less类模板时,如果需要使用自定义类型,都是传入严格弱排序的仿函数,比如中的sort函数和priority_queue的模板实参。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值