【STL九】关联容器——map容器、multimap容器

一、map简介

在这里插入图片描述

  • map 容器存储的都是 pair 对象,也就是用 pair 类模板创建的键值对。
  • key和value都必须是可复制的(copyable),可移动的(movable);
  • 在使用 map 容器存储多个键值对时,该容器会自动根据各键值对的键的大小,按照既定的规则进行排序。

默认情况下,map 容器选用std::less排序规则(其中 T 表示键的数据类型),其会根据键的大小对所有键值对做升序排序。当然,根据实际情况的需要,我们可以手动指定 map 容器的排序规则,既可以选用 STL 标准库中提供的其它排序规则(比如std::greater)

  • 对于指定的排序准则而言,key必须是可比较的(comparable)。

使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改

二、头文件

#include<map>

三、模板类

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T>>
> class map;

四、map的内部结构

  • map/multimap通常以平衡二叉树完成;(同其他关联容器)
  • map和multimap会根据元素的key自动对元素排序。
    • 这样一来,根据已知的key查找某个元素时就能够有很好的效率,
    • 而根据已知的value查找元素时,效率就很糟糕。
  • 自动排序这一性质使得map和multimap身上有一个很重要的限制:你不可以直接改变元素的key.(因为这会破坏正确次序)

要修改元素的key,必须先移除拥有该key的元素,然后插入拥有新key/value的元素。(如果value非常量,就可以修改)

在这里插入图片描述

五、成员函数

1、迭代器

成员函数 功能
begin() array容器
end() array容器
rbegin() array容器
rend() array容器
cbegin() array容器
cend() array容器
crbegin() array容器
crend() array容器

2、元素访问

成员函数 功能
operator[] array容器
at(n) array容器
front() 同array容器
back() 同array容器
data() 同array容器

3、容量

成员函数 功能
size() array容器
max_size() array容器
empty() array容器
reserve 同vector容器
capacity 同vector容器
shrink_to_fit 同vector容器

4、修改操作

成员函数 功能
clear() vector容器
insert() vector容器
insert_or_assign(C++17) 插入元素,或若键已存在则赋值给当前元素
emplace() vector容器
emplace_hint() 在本质上和 emplace() 在 map 容器中构造新键值对的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示键值对生成位置的迭代器,并作为该方法的第一个参数。
try_emplace(C++17) 若键不存在则原位插入,若键存在则不做任何事
erase() vector容器
push_back() 同vector容器
emplace_back() 同vector容器
pop_back() 同vector容器
push_front() 同vector容器
emplace_front() 同vector容器
pop_front() 同vector容器
resize() 同vector容器
swap() vector容器
extract(C++17) 从另一容器释出结点
merge(C++17) 从另一容器接合结点

5、操作

成员函数 功能
merge() list容器
splice() list容器
remove(val) list容器
remove_if() list容器
reverse() list容器
unique() list容器
sort() list容器

5、查找

成员函数 功能
count(key) 在当前 map 容器中,查找键为 key 的键值对的个数并返回。注意,由于 map 容器中各键值对的键的值是唯一的,因此该函数的返回值最大为 1。
find(key) 在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
contains (C++20) 检查容器是否含有带特定键的元素
equal_range(key) 该方法返回一个 pair 对象(包含 2 个双向迭代器),其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为 key 的键值对(map 容器键值对唯一,因此该范围最多包含一个键值对)。
lower_bound(key) 返回一个指向当前 map 容器中第一个大于或等于 key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
upper_bound(key) 返回一个指向当前 map 容器中第一个大于 key 的键值对的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

6、查看操作

成员函数 功能
key_comp 返回用于比较键的函数
value_comp 返回用于在value_type类型的对象中比较键的函数。

六、demo

1、查找find

  • 返回值
    指向键等于 key 的元素的迭代器。若找不到这种元素,则返回尾后(见 end() )迭代器。
#include <iostream>
#include <string>       // string
#include<map>
using namespace std;
int main() {
    
    
    // 调用构造函数 1,也就是默认构造函数
    map <string, string> mymap{
    
    
        {
    
    "小b","家在西安"},
        {
    
    "小c","家在濮阳"},
        {
    
    "小a","家在北京"},
        {
    
    "小d","没有家"},
    };
    
    cout << "i can find 小c:" << endl;

    auto ite = mymap.find("小c");
    cout << ite->first << "=" << ite->second << endl << endl;

    auto ite2 = mymap.find("c");
    if (ite2 == mymap.end())
    {
    
    
        cout << "i can not find c!" << endl;
        // cout << ite->first << "=" << ite->second << endl << endl; //找不到时输出会报错的
    }
    return 0;
}

输出

i can find 小c:
小c=家在濮阳

i can not find c!

2、查找lower_bound、upper_bound

返回值

  • lower_bound:指向首个不小于 key 的元素的迭代器。若找不到这种元素,则返回尾后迭代器
  • upper_bound:指向首个大于 key 的元素的迭代器。若找不到这种元素,则返回尾后迭代器

正常场景

#include <iostream>
#include <string>       // string
#include<map>
using namespace std;
int main() {
    
    
    // 调用构造函数 1,也就是默认构造函数
    map <string, string> mymap{
    
    
        {
    
    "小b","家在西安"},
        {
    
    "小c","家在濮阳"},
        {
    
    "小a","家在北京"},
        {
    
    "小d","没有家"},
    };
    
    //找到第一个键的值不小于 "小c" 的键值对
    auto iter = mymap.lower_bound("小c");
    cout << "lower:" << iter->first << " " << iter->second << endl;

    //找到第一个键的值大于 "小c 的键值对
    iter = mymap.upper_bound("小c");
    cout << "upper:" << iter->first << " " << iter->second << endl;
    
    return 0;
}

输出

lower:小c 家在濮阳
upper:小d 没有家

临界场景

#include <iostream>
#include <string>       // string
#include<map>
using namespace std;
int main() {
    
    
    // 调用构造函数 1,也就是默认构造函数
    map <string, string> mymap{
    
    
        {
    
    "小b","家在西安"},
        {
    
    "小c","家在濮阳"},
        {
    
    "小a","家在北京"},
        {
    
    "小d","没有家"},
    };
    
    //找到第一个键的值不小于 "小c" 的键值对
    auto iter = mymap.lower_bound("小d");
    cout << "lower:" << iter->first << " " << iter->second << endl;

    //找到第一个键的值大于 "小c 的键值对
    iter = mymap.upper_bound("小d");
    if (iter == mymap.end())
    {
    
    
        cout << "i can not find uper load 小d!" << endl;
    }

    return 0;
}

输出

lower:小d 没有家
i can not find uper load 小d!

3、insert、emplace() 和 emplace_hint()

  • insert
    insert() 方法返回的是迭代器,而不再是 pair 对象:
    • 如果插入成功,insert() 方法会返回一个指向 map 容器中已插入键值对的迭代器;
    • 如果插入失败,insert() 方法同样会返回一个迭代器,该迭代器指向 map 容器中和 val 具有相同键的那个键值对。
#include <iostream>
#include <string>       // string
#include<map>
using namespace std;
int main() {
    
    
    // 调用构造函数 1,也就是默认构造函数
    map <string, string> mymap{
    
    
        {
    
    "小b","家在西安"},
        {
    
    "小c","家在濮阳"},
        {
    
    "小a","家在北京"},
        {
    
    "小d","没有家"},
    };
    
    auto ret = mymap.insert({
    
     "小e","家在台湾"});
    cout << "insert:" << ret.first->first << " " << ret.first->second << "=" << ret.second << endl;

    ret = mymap.insert({
    
     "小e","家在台湾" });
    cout << "insert:" << ret.first->first << " " << ret.first->second << "=" << ret.second << endl;

    return 0;
}

输出

insert:小e 家在台湾=1
insert:小e 家在台湾=0

  • emplace
    emplace() 和 emplace_hint() 是 C++ 11 标准加入到 set 类模板中的,相比具有同样功能的 insert() 方法,完成同样的任务,emplace() 和 emplace_hint() 的效率会更高。
#include <iostream>
#include <string>       // string
#include<map>
using namespace std;
int main() {
    
    
    // 调用构造函数 1,也就是默认构造函数
    map <string, string> mymap{
    
    
        {
    
    "小b","家在西安"},
        {
    
    "小c","家在濮阳"},
        {
    
    "小a","家在北京"},
        {
    
    "小d","没有家"},
    };
    
    auto ret = mymap.emplace( "小e","家在台湾");
    cout << "emplace:" << ret.first->first << " " << ret.first->second << "=" << ret.second << endl;

    ret = mymap.emplace( "小e","家在台湾" );
    cout << "emplace:" << ret.first->first << " " << ret.first->second << "=" << ret.second << endl;

    return 0;
}

输出

emplace:小e 家在台湾=1
emplace:小e 家在台湾=0

  • emplace_hint
#include <iostream>
#include <string>       // string
#include<map>
using namespace std;
int main() {
    
    
    // 调用构造函数 1,也就是默认构造函数
    map <string, string> mymap{
    
    
        {
    
    "小b","家在西安"},
        {
    
    "小c","家在濮阳"},
        {
    
    "小a","家在北京"},
        {
    
    "小d","没有家"},
    };
    
    auto iter = mymap.emplace_hint(mymap.begin(), "小e","家在台湾");
    cout << "emplace_hint:" << iter->first << " " << iter->second << endl;

    iter = mymap.emplace_hint(mymap.begin(), "小e", "家在台湾");
    cout << "emplace_hint:" << iter->first << " " << iter->second << endl;

    return 0;
}

输出

emplace_hint:小e 家在台湾
emplace_hint:小e 家在台湾

虽然 emplace_hint() 方法指定了插入键值对的位置,但 map 容器为了保持存储键值对的有序状态,可能会移动其位置。(如下图)
在这里插入图片描述

七、multimap

map 容器的区别在于,multimap 容器中可以同时存储多(≥2)个键相同的键值对。

由于 multimap 容器可存储多个具有相同键的键值对,因此表 1 中的 lower_bound()、upper_bound()、equal_range() 以及 count() 成员方法会经常用到。

  • 模板类
multimap 容器类模板的定义如下:
template < class Key,                                   // 指定键(key)的类型
           class T,                                     // 指定值(value)的类型
           class Compare = less<Key>,                   // 指定排序规则
           class Alloc = allocator<pair<const Key,T> >  // 指定分配器对象的类型
           > class multimap;
  • demo
template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T> >
> class multimap;
  • demo
#include <iostream>
#include <string>       // string
#include<map>
using namespace std;
int main() {
    
    
    // 调用构造函数 1,也就是默认构造函数
    multimap <string, string> mymultimap{
    
    
        {
    
    "小b","家在西安"},
        {
    
    "小c","家在濮阳"},
        {
    
    "小a","家在北京"},
        {
    
    "小d","没有家"},
        {
    
    "小d","也没有家"},
    };

    //输出 mymultimap 容器中存储键为 'b' 的键值对的数量
    cout << mymultimap.count("小d") << endl;
    
    for (auto iter = mymultimap.begin(); iter != mymultimap.end(); ++iter) {
    
    
        cout << iter->first << " " << iter->second << endl;
    }

    return 0;
}

2
小a 家在北京
小b 家在西安
小c 家在濮阳
小d 没有家
小d 也没有家

参考:
1、C++ STL 容器库 中文文档
2、STL教程:C++ STL快速入门
3、https://www.apiref.com/cpp-zh/cpp/header.html
4、https://en.cppreference.com/w/cpp/container

猜你喜欢

转载自blog.csdn.net/junxuezheng/article/details/129335386