[STL 9] Associative container - map container, multimap container

1. Introduction to map

insert image description here

  • The map container stores all pair objects, that is, key-value pairs created with the pair class template.
  • Both key and value must be copyable (copyable), movable (movable);
  • When using the map container to store multiple key-value pairs, the container will automatically sort according to the established rules according to the size of the key of each key-value pair.

By default, the map container uses the std::less sorting rule (where T represents the data type of the key), which sorts all key-value pairs in ascending order according to the size of the key. Of course, according to the needs of the actual situation, we can manually specify the sorting rules of the map container, or choose other sorting rules provided in the STL standard library (such as std::greater)

  • Keys must be comparable for the specified ordering criteria.

Use each key-value pair stored in the map container, and the value of the key can neither be repeated nor modified

Two, the header file

#include<map>

3. Template class

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

Fourth, the internal structure of the map

  • map/multimap is usually done as a balanced binary tree; (same as other associative containers)
  • Map and multimap will automatically sort the elements according to the key of the element.
    • In this way, it can be very efficient when searching for an element based on a known key.
    • When looking up elements based on known values, the efficiency is very bad.
  • The nature of automatic sorting makes maps and multimaps have an important limitation: you cannot directly change the key of the element. (Because this will destroy the correct order)

To modify the key of an element, the element with the key must be removed first, and then the element with the new key/value must be inserted. (If the value is not constant, it can be modified)

insert image description here

5. Member functions

1. Iterator

member function Function
begin() Same array container
end() Same array container
rbegin() Same array container
rend() Same array container
cbegin() Same array container
a few() Same array container
crbegin() Same array container
crend() Same array container

2. Element access

member function Function
operator[] Same array container
at(n) Same array container
front() Same array container
back() Same array container
data() Same array container

3. Capacity

member function Function
size() Same array container
max_size() Same array container
empty() Same array container
reserve Same as vector container
capacity Same as vector container
shrink_to_fit Same as vector container

4. Modify operation

member function Function
clear() Same as vector container
insert() Same as vector container
insert_or_assign(C++17) inserts the element, or assigns to the current element if the key already exists
place() Same as vector container
emplace_hint() It is essentially the same as how emplace() constructs a new key-value pair in a map container. The difference is that the user must provide this method with an iterator indicating the location where the key-value pair is generated, and use it as the method's first parameter.
try_emplace(C++17) Insert in place if the key does not exist, do nothing if the key exists
erase() Same as vector container
push_back() Same as vector container
emplace_back() Same as vector container
pop_back() Same as vector container
push_front() Same as vector container
emplace_front() Same as vector container
pop_front() Same as vector container
resize() Same as vector container
swap() Same as vector container
extract(C++17) release a node from another container
merge(C++17) join node from another container

5. Operation

member function Function
merge() list container
splice() list container
remove(val) list container
remove_if() list container
reverse() list container
unique() list container
sort() list container

5. Find

member function Function
count(key) In the current map container, find the number of key-value pairs whose key is key and return it. Note that since the key value of each key-value pair in the map container is unique, the maximum return value of this function is 1.
find(key) Look up the key-value pair whose key is key in the map container. If found successfully, return a bidirectional iterator pointing to the key-value pair; otherwise, return the same iterator as the end() method. In addition, if the map container is const-qualified, this method returns a bidirectional iterator of const type.
contains (C++20) Checks if a container contains an element with a specific key
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 容器为了保持存储键值对的有序状态,可能会移动其位置。(如下图)
insert image description here

七、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
Little a lives in Beijing
Little b lives in Xi’an
Little c lives in Puyang
Little d has no home
Little d has no home either

References:
1. C++ STL Container Library Chinese Documentation
2. STL Tutorial: C++ STL Quick Start
3. https://www.apiref.com/cpp-zh/cpp/header.html
4. https://en.cppreference. com/w/cpp/container

Guess you like

Origin blog.csdn.net/junxuezheng/article/details/129335386