c++ map,multimap

关联式容器(Associative Container)

关联式容器依据特定的排序准则,自动为其元素排序。元素可以是任何类型的 value,也可以是 key/value pair,其中 key 可以是任何类型,映射至一个相关 value,而 value 也可以是任意类型。排序准则以函数形式呈现,用来比较 value,或比较 key/value 中的 key 。默认情况下所以容器都以操作符 < 进行比较,但是你可以提供自己的比较函数,定义不同的排序准则。
通常关联式容器由二叉树实现出来。在二叉树中,每个元素(节点)都有一个父节点和两个子节点,左子树的所有元素都比自己小,右子树的所有元素都比自己大。关联容器的差别主要在于元素的种类以及处理重复元素时的方式。
关联式容器的主要优点是,它能很快找出一个具有某特定 value 的元素,因为它具备对数复杂度,而任何循序式容器的复杂度是线性。因此,使用关联式容器,面对1000个元素,平均而言你将有10次而不是500次比较动作。然而它有一个缺点是,你不能直接改动元素的 value ,因为那会破坏元素的自动排序。

下面是 STL 定义的关联式容器:

set 元素依据其 value 自动排序。每个元素只能出现一次,不允许重复。
multiset 和 set 的唯一差别是:元素可以重复。也就是 multiset 可包括多个 "value相同"的元素。
map 每个元素都是 key/value pair,其中 key 是排序准则的基准。每个 key 只能出现一次,不允许重复。
multimap 和 map 的唯一差别是:元素可以重复,也就是 multimap 允许其元素拥有相同的 key。

map

template <typename Key, typename Tp, typename Compare = std::less<Key>,
	    typename Alloc = std::allocator<std::pair<const Key, Tp> > >
    class map
    {
    public:
      typedef Key					key_type; // 第一个参数模板 Key
      typedef Tp					mapped_type; // 第二个参数模板 Tp
      typedef std::pair<const Key, Tp>		value_type;
      typedef Compare					key_compare;
      typedef Alloc					allocator_type;
      typedef typename Alloc_traits::pointer		 pointer;
      typedef typename Alloc_traits::const_pointer	 const_pointer;
      typedef typename Alloc_traits::reference		 reference;
      typedef typename Alloc_traits::const_reference	 const_reference;
      typedef typename Rep_type::iterator		 iterator; // value_type的双向迭代器
      typedef typename Rep_type::const_iterator	 const_iterator; // const value_type的双向迭代器
      typedef typename Rep_type::size_type		 size_type; // 无符号整数类型
      typedef typename Rep_type::difference_type	 difference_type; // 一个有符号整数类型
      typedef typename Rep_type::reverse_iterator	 reverse_iterator;
      typedef typename Rep_type::const_reverse_iterator const_reverse_iterator;
};

默认构造

//定义一个默认状态的空map容器
explicit map (const key_compare& comp = key_compare(), const allocator_type& alloc = allocator_type());

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

int main()
{
    map<string,int> arr1;//定义一个空的map容器

    map<string,int> arr2{
            {"小明",10086},
            {"小红",1008611},
            {"小兰",123456}
    };//使用初值列定义一个包含三个string/int的map容器
    for(auto i:arr2) //输出所有元素
        cout<<i.first<<" "<<i.second<<endl;
    cout<<endl;

    map<string,int> arr3(arr2);//使用一个map容器作为初始值
    for(auto i:arr3) //输出所有元素
        cout<<i.first<<" "<<i.second<<endl;
    cout<<endl;

    map<string,int> arr4(++arr2.begin(),arr2.end());//使用迭代器赋值
    for(auto i:arr4) //输出所有元素
        cout<<i.first<<" "<<i.second<<endl;
}

自定义排序准则

//自定义比较方法
explicit map(const key_compare& comp, const allocator_type& a = allocator_type());

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

bool upper(int a,int b){return a>b;} //自定义大到小比较函数
bool lower(int a,int b){return a<b;} //自定义小到大比较函数

int main()
{
    map<int,string,bool(*)(int,int)> arr({{1,"小红"},{3,"小明"},{2,"小兰"}},lower);//按照key从小到大排列
    for(auto i:arr)
        cout<<i.first<<" "<<i.second<<endl;

    cout<<endl;

    map<int,string,bool(*)(int,int)> buf({{1,"小红"},{3,"小明"},{2,"小兰"}},upper);//按照key从大到小排列
    for(auto i:buf)
        cout<<i.first<<" "<<i.second<<endl;
}

用自定义的函数对象来比较元素

如果 map 或 multimap 中的键是指针的话,那么需要定义一个函数来比较它们所指向的对象,否则会比较指针所表示的地址,这并不是我们想要的。如果键是不支持直接进行 < 或 > 比较的类型,为了可以在 map 或 multimap 中使用它们,必须为它们定义一个适当的函数对象。处理这两种情况的方式在本质上相同。

#include<iostream>
#include<map>
#include<string>
#include<memory>
using namespace std;

class Key_compare
{
public:
    bool operator () (const unique_ptr<string>& p1, const unique_ptr <string>& p2) const
    {
        return *p1 < *p2;
    }
};

int main()
{
    map<unique_ptr<string>,string,Key_compare> phonebook;
    phonebook.emplace(make_unique<string>("Fred"), "914-626-7897");
    phonebook.insert(make_pair(make_unique<string>("Lily"), "212-896-4337"));
    phonebook.emplace(make_unique<string>("Eloik"), "871-343-4714");

    for (const auto& p: phonebook)
        cout << *p.first << " " << p.second << endl;
}

赋值

操作符= 功能是将值赋给map对象,值可以为一个map容器,也可以是一个初值列。

map&operator =const map&x);
map&operator =(map && x);
map&operator =(initializer_list <value_type> il);

swap 功能为交换两个map容器。

void swap (map& x);

无论是= 还是 swap,操作两个不同的容器时,其key/value 必须一致。

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

bool upper(string a,string b){return a>b;}

int main()
{
    map<string,int> arr1;
    map<string,int> arr2;
    map<string,int> arr3;
    map<string,int,bool(*)(string,string)> arr4(upper);
    map<string,char> arr5;

    arr1 = { {"小明",10086},
             {"小红",1008611},
             {"小兰",123456}}; //使用初值列赋值
    arr2 = arr1; //使用容器赋值
    arr3["小黑"] = 666666; //使用数组的方法赋值
    arr1.swap(arr3); //交换两个容器

    //arr2 = arr4;//错误 参数模板 不一致
    //arr2 = arr5;//错误 key/value 不一致
    //arr2.swap(arr4); //错误 参数模板 不一致
    //arr2.swap(arr5); //错误 key/value 不一致
}

multimap

multimap 容器保存的是有序的键/值对,但它可以保存重复的元素(重复键的排序方式为:不改变其相对顺序)。multimap 中会出现具有相同键的元素序列,它们会被添加到容器中。multimap 和 map 有相同范围的构造函数,默认的比较键的函数是 less()。

multimap 大部分成员函数的使用方式和 map 相同。因为重复键的原因,multimap 有一些函数的使用方式和 map 有一些区别。

#include<iostream>
#include<map>
#include<string>
#include<algorithm>
#include<utility>
using namespace std;

int main()
{
    multimap<string, size_t> people {{"Ann",44},{"Ann",25},{"Bill", 46}, {"Jack", 77},
                                     {"Jack", 32},{"Jill", 32}, {"Ann", 35}};
    auto it = people.find("Ann");//输出指向第一个Ann的迭代器
    if(it != people.end())
        cout<<it->first<<" "<<it->second<<endl;
    cout<<endl;
    auto pr = people.equal_range("Ann");//遍历所有键为 Ann 的元素
    if(pr.first != end(people))
    {
        for (auto iter = pr.first ; iter != pr.second; ++iter)
            cout << iter->first << " is " << iter->second << endl;
    }
    
    auto iter1 = people.lower_bound("Ann");
    auto iter2 = people.upper_bound("Ann");
    if(iter1 != end(people))
    {
        for(auto iter = iter1 ; iter != iter2; ++iter)
            cout << iter->first << " is " << iter->second << endl;
    }
}

equal_range() 的参数可以是和键同类型的对象,或是不同类型的但可以和键比较的对象。返回的 pair 对象的成员变量 first 是一个迭代器,它指向第一个大于等于参数的元素;如果键和参数相等的元素存在的话,它是第一个键和参数相同的元素。如果键不存在,pair 的成员变量 first 就是容器的结束迭代器,所以应该总是对它们进行捡查。

pair 的成员变量 second 也是一个迭代器,它指向键值大于参数的第一个参数;如果没有这样的元素,它会是一个结束迭代器。

multimap 的成员函数 lower_bound() 会返回一个迭代器,它指向键值和参数相等或大于参数的第一个元素,或者指向结束迭代器。upper_bound() 也返回一个迭代器,它指向键值大于函数参数的第一个元素,如果这样的元素不出现的话,它就是一个结束迭代器。所以,当存在一个或多个相等键时,这些函数会返回一个开始迭代器和一个结束迭代器,它们指定了和参数匹配的元素的范围,这和 equal_range() 返回的迭代器是相同的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值