• 浅谈C++|STL之map篇


    在这里插入图片描述

    一.map

    1.1map概念

    简介:

    • map中所有元素都是pair
    • pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
    • 所有元素都会根据元素的键值自动排序

    本质:

    • . map/multimap属于关联式容器,底层结构是用二叉树实现。

    优点:

    • 可以根据key值快速找到value值

    map和multimap区别:

    • map不允许容器中有重复key值元素

    • multimap允许容器中有重复key值元素

    1.2pair模板类

    作用

    std::pair 是 C++ 标准库中定义的一个模板类,用于将两个值组合为一个类型。它提供了简单的方式来存储和操作两个不同类型的值。

    以下是 std::pair 的一些特点和用法:

    1. 创建 pair 对象:

      • 使用构造函数,可以指定两个值。
    2. 访问 pair 对象的值:

      • 通过 firstsecond 成员变量,分别访问第一个和第二个值。
    3. 比较 pair 对象:

      • 支持 ==!=<<=>>= 运算符的比较操作。
    4. 作为函数的返回值:

      • pair 可以用作函数的返回值,这样可以方便地返回多个值。
    5. 作为容器的元素:

      • pair 可以作为容器(如 vectormap 等)的元素,以存储多个不同类型的值。

    例如,以下是使用 std::pair 的一个示例:

    #include 
    #include 
    
    int main() {
        std::pair<int, std::string> myPair(1, "Hello");
        std::cout << myPair.first << " " << myPair.second << std::endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上述代码创建了一个 pair 对象 myPair,其中第一个值为 1,第二个值为 "Hello"。在输出时,可以使用 firstsecond 成员变量来访问这两个值,并输出结果为 1 Hello

    std::pair 在许多情况下都非常有用,特别是当需要将两个不同类型的值作为一个实体使用时。

    创建方式

    std::pair 可以通过多种方式进行创建,以下是几种常见的创建方式:

    1. 使用构造函数:

      • 使用带有参数的构造函数来创建 pair 对象,需要指定两个值的类型。
      std::pair<int, std::string> myPair(1, "Hello");
      
      • 1
    2. 使用 std::make_pair() 函数:

      • 使用 std::make_pair() 函数可以更方便地创建 pair 对象,不需要显式指定类型。
      auto myPair = std::make_pair(1, "Hello");
      
      • 1
    3. 使用初始化列表:

      • 可以使用初始化列表来创建 pair 对象,并指定两个值。
      std::pair<int, std::string> myPair = {1, "Hello"};
      
      • 1
    4. pair 作为函数的返回值:

      • pair 可以作为函数的返回值,将多个值一起返回。
      std::pair<int, std::string> getValues() {
          return std::make_pair(1, "Hello");
      }
      
      • 1
      • 2
      • 3

    上述示例中,创建了一个 pair 对象,并指定了两个值。可以根据需要选择适合的方式来创建 pair 对象。无论使用哪种方式,pair 都可以方便地将两个不同类型的值组合为一个对象。

    创建方式示例代码
    构造函数std::pair myPair(1, "Hello");
    std::make_pair()auto myPair = std::make_pair(1, "Hello");
    初始化列表std::pair myPair = {1, "Hello"};
    作为函数返回值std::pair getValues() { return std::make_pair(1, "Hello"); }

    1.3map的构造和赋值

    map数据类型只能是各种pair

    1. 默认构造函数:

      • 使用默认构造函数创建一个空的 map 容器。
      std::map<KeyType, ValueType> myMap;
      
      • 1
    2. 初始化列表构造函数:

      • 使用初始化列表构造函数,可以在创建 map 的同时初始化一些键-值对。
      std::map<KeyType, ValueType> myMap = { {key1, value1}, {key2, value2}, ... };
      
      • 1
    3. 范围构造函数:

      • 使用另一个容器的范围构造函数,可以将其他容器的内容复制到一个新的 map 中。
      std::map<KeyType, ValueType> myMap(otherContainer.begin(), otherContainer.end());
      
      • 1
    4. 拷贝构造函数:

      • 使用另一个 map 的拷贝构造函数,可以创建一个已有 map 的副本。
      std::map<KeyType, ValueType> myMap(otherMap);
      
      • 1
    5. 赋值运算符:

      • 使用赋值运算符,将一个 map 的内容赋值给另一个 map
      std::map<KeyType, ValueType> myMap;
      myMap = otherMap;
      
      • 1
      • 2
    6. 移动构造函数和移动赋值运算符:

      • C++11 引入了移动语义,可以使用移动构造函数和移动赋值运算符来高效地将一个 map 的内容移动到另一个 map 中,避免不必要的复制。
      std::map<KeyType, ValueType> myMap(std::move(otherMap));  // 移动构造函数
      myMap = std::move(otherMap);  // 移动赋值运算符
      
      • 1
      • 2

    这些是使用 map 的常见构造和赋值方式。根据实际需求,选择适当的方法来构造和赋值 map 对象。

    构造/赋值方式示例代码
    默认构造函数std::map myMap;
    初始化列表构造函数std::map myMap = { {key1, value1}, {key2, value2}, ... };
    范围构造函数std::map myMap(otherContainer.begin(), otherContainer.end());
    拷贝构造函数std::map myMap(otherMap);
    赋值运算符std::map myMap; myMap = otherMap;
    移动构造函数std::map myMap(std::move(otherMap));
    移动赋值运算符myMap = std::move(otherMap);

    1.4map的大小和交换

    在C++中,std::map 提供了几种常用的成员函数来获取大小以及进行交换操作。

    1. 获取大小:

      • size() 函数可以返回当前 map 中键值对的数量。
      std::map<KeyType, ValueType> myMap;
      int size = myMap.size();
      
      • 1
      • 2
    2. 判断是否为空:

      • empty() 函数可以判断 map 是否为空,返回一个布尔值表示是否为空。
      std::map<KeyType, ValueType> myMap;
      bool isEmpty = myMap.empty();
      
      • 1
      • 2
    3. 交换 map:

      • swap() 函数可以交换两个 map 容器的内容。
      std::map<KeyType, ValueType> map1;
      std::map<KeyType, ValueType> map2;
      // 交换 map1 和 map2 的内容
      map1.swap(map2);
      
      • 1
      • 2
      • 3
      • 4

    使用这些操作可以方便地获取 map 的大小,并且在需要时交换 map 容器的内容。记住,在交换时,map 中的元素会被交换,并且两个 map 的键值对会互相替换。

    操作示例代码
    获取大小std::map myMap;
    int size = myMap.size();
    判断是否为空std::map myMap;
    bool isEmpty = myMap.empty();
    交换 mapstd::map map1;
    std::map map2;
    map1.swap(map2);

    1.5map的插入和删除

    在 C++ 中,std::map 提供了几种用于插入和删除元素的成员函数和操作符。

    1. 插入元素:

      • 使用 insert() 函数可以插入一个键值对或一对迭代器范围的键值对。
      std::map<KeyType, ValueType> myMap;
      
      // 单个插入
      myMap.insert(std::make_pair(key, value));
      
      // 插入多个元素
      std::map<KeyType, ValueType> anotherMap;
      myMap.insert(anotherMap.begin(), anotherMap.end());
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    2. 删除元素:

      • 使用 erase() 函数可以删除指定键的元素,也可以使用迭代器来删除一个或一段元素。
      std::map<KeyType, ValueType> myMap;
      
      // 删除指定键的元素
      myMap.erase(key);
      
      // 删除迭代器指向的元素
      std::map<KeyType, ValueType>::iterator it = myMap.find(key);
      if (it != myMap.end()) {
          myMap.erase(it);
      }
      
      // 删除元素范围
      myMap.erase(myMap.begin(), myMap.end());
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    3. 清空 map:

      • 使用 clear() 函数可以清空整个 map 容器中的所有元素。
      std::map<KeyType, ValueType> myMap;
      myMap.clear();
      
      • 1
      • 2

    这些是 std::map 插入和删除元素的常见操作。根据实际需求,选择适当的方法来插入和删除 map 中的元素。

    操作示例代码
    插入单个元素std::map myMap;
    myMap.insert(std::make_pair(key, value));
    插入多个元素std::map myMap;
    std::map anotherMap;
    myMap.insert(anotherMap.begin(), anotherMap.end());
    删除指定键的元素std::map myMap;
    myMap.erase(key);
    删除迭代器指向的元素std::map myMap;
    std::map::iterator it = myMap.find(key);
    if (it != myMap.end()) { myMap.erase(it); }
    删除元素范围std::map myMap;
    myMap.erase(myMap.begin(), myMap.end());
    清空 mapstd::map myMap;
    myMap.clear();

    1.6map的查找和统计

    在 C++ 中,std::set 提供了几种用于查找和统计元素的成员函数。

    1. 查找元素:

      • 使用 find() 函数来查找指定值的元素,如果找到则返回指向该元素的迭代器,否则返回 end() 迭代器。
      std::set<ValueType> mySet;
      
      // 查找指定值的元素
      std::set<ValueType>::iterator it = mySet.find(value);
      if (it != mySet.end()) {
          // 元素找到
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    2. 统计元素个数:

      • 使用 count() 函数来统计指定值的元素在 set 中出现的次数。
      std::set<ValueType> mySet;
      
      // 统计指定值的元素个数
      int count = mySet.count(value);
      
      • 1
      • 2
      • 3
      • 4
    3. 判断元素是否存在:

      • 使用 count() 函数来判断指定值的元素是否存在于 set 中(存在时返回 1 个或更多的计数)。
      std::set<ValueType> mySet;
      
      // 判断指定值的元素是否存在
      bool exists = mySet.count(value) > 0;
      
      • 1
      • 2
      • 3
      • 4

    这些是 std::set 查找和统计元素的常见操作。你可以根据实际需求,使用这些函数来查找特定的元素并统计元素的个数。

    操作示例代码
    查找指定值的元素std::set mySet;
    std::set::iterator it = mySet.find(value);
    if (it != mySet.end()) { /* 元素找到 */ }
    统计指定值的个数std::set mySet;
    int count = mySet.count(value);
    判断元素是否存在std::set mySet;
    bool exists = mySet.count(value) > 0;

    这个表格将 set 的查找和统计操作整理成了一个简洁的表格。你可以根据实际需求使用这些操作来查找指定值的元素、获取指定值在集合中的个数,或者判断元素是否存在于集合中。

    1.7map容器排序

    map容器排序,和set排序一样,都需要借用仿函数。
    在 C++ 中,std::map 是一个关联容器,按照键的自动排序进行存储。默认情况下,std::map 使用键的升序进行排序。但如果你希望按照其他方式进行排序,可以通过自定义比较函数来实现。

    以下是一些实现 std::map 容器排序的示例代码:

    #include 
    #include 
    #include 
    
    // 自定义比较函数,按照值的降序进行排序
    struct CompareByValue {
        bool operator()(const int& a, const int& b) const {
            return a > b; // 使用大于号实现降序
        }
    };
    
    int main() {
        std::map<int, std::string> myMap; // 默认按照键的升序排序
    
        // 添加元素
        myMap.insert(std::make_pair(3, "C"));
        myMap.insert(std::make_pair(1, "A"));
        myMap.insert(std::make_pair(2, "B"));
    
        // 遍历输出,默认按照键的升序输出
        std::cout << "默认升序排序:" << std::endl;
        for (const auto& pair : myMap) {
            std::cout << pair.first << ": " << pair.second << std::endl;
        }
    
        // 使用自定义比较函数,按照值的降序排序
        std::map<int, std::string, CompareByValue> sortedMap;
    
        // 复制原始 map 的元素到排序后的 map
        sortedMap.insert(myMap.begin(), myMap.end());
    
        // 遍历输出,按照值的降序输出
        std::cout << "按值降序排序:" << std::endl;
        for (const auto& pair : sortedMap) {
            std::cout << pair.first << ": " << pair.second << std::endl;
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在示例代码中,CompareByValue 结构体是一个自定义的比较函数对象,实现了按照值的降序进行排序。在创建 std::map 容器时,可以传入 CompareByValue 类型作为第三个模板参数来指定自定义比较函数。

    注:如果你想对 std::map 进行临时排序而不影响原始数据的排序,你可以使用 std::multimap 或在复制数据后进行排序。

    二.multimap

    multimap是键值可以重复的map。

    std::mapstd::multimap 之间的区别:

    1. 唯一性:std::map 要求键的唯一性,每个键只能对应一个值。而 std::multimap 允许键的重复,即可以存储多个具有相同键的值。

    2. 排序:std::map 按照键的默认严格弱序进行排序,这有助于提高搜索效率。默认情况下,键是按照升序排序的。而 std::multimap 也按照键的默认严格弱序进行排序,即也是按照升序排序的。

    3. 删除:对于 std::map,删除给定键的元素将删除具有该键的唯一元素。而对于 std::multimap,删除给定键的元素将删除所有具有该键的元素。

    4. multimap没有重载[ ],map可以直接用[]访问,修改,插入数据。

    总结起来,std::map 适合存储唯一键值对并按照键进行排序的场景。而 std::multimap 适合存储允许键重复的键值对,并且也可以按照键进行排序。

    三.unordered_map

    在函数接口方面,std::mapstd::unordered_map 之间有一些区别和差异。以下是其中的一些主要区别:

    1. 插入元素:对于 std::map,可以使用 insert() 函数或 [] 运算符插入一个键值对。如果已经存在相同的键,则插入不会生效。而对于 std::unordered_map,也可以使用 insert() 函数或 [] 运算符插入一个键值对,但如果已经存在相同的键,则新的值将取代旧的值。

    2. 查找元素:对于 std::map,可以使用 find() 函数根据键查找元素,并返回一个迭代器指向找到的元素,如果没找到则返回末尾迭代器。而对于 std::unordered_map,也可以使用 find() 函数根据键查找元素,返回一个迭代器指向找到的元素,如果没找到则返回和 end() 相等的迭代器。

    3. 访问元素:对于 std::map,可以使用 [] 运算符根据键访问元素的值。而对于 std::unordered_map,同样可以使用 [] 运算符根据键访问元素的值。

    4. 删除元素:对于 std::map,可以使用 erase() 函数删除给定键的元素,如果存在多个具有相同键的元素,只会删除第一个匹配的元素。而对于 std::unordered_map,可以使用 erase() 函数删除给定键的元素,它会删除所有具有相同键的元素。

    除了上述不同之外,其他函数接口如迭代器操作、大小操作、清除容器等方面在 std::mapstd::unordered_map 中基本上是相似的。

    四.unordered_multimap

    std::mapstd::unordered_map 是两个不同的关联容器,而 std::unordered_multimap 则是 std::unordered_map 的多重键版本。下面是 std::unordered_multimapstd::map 的一些主要区别:

    1. 允许重复键:在 std::map 中,每个键只能对应唯一的值,如果插入具有相同键的元素,则会替换旧值。然而,在 std::unordered_multimap 中,可以插入具有相同键的多个元素,并且允许重复键的存在。

    2. 元素顺序:std::map 是有序关联容器,它按照键的严格弱顺序进行排序。在遍历 std::map 时,元素将按照排序顺序访问。而 std::unordered_multimap 是无序关联容器,它不保证元素的顺序,元素的存储和访问顺序可能会有所不同。

    3. 查找效率:由于 std::unordered_multimap 基于哈希表实现,查找操作的平均时间复杂度接近 O(1),而 std::map 则是基于红黑树,查找操作的平均时间复杂度为 O(log n)。

    4. 插入顺序:在 std::map 中,每个元素按照键的顺序进行插入。而在 std::unordered_multimap 中,元素的插入顺序与它们的哈希值相关,哈希值不一样的元素可能会以不同的顺序插入。

    根据需要,选择使用 std::mapstd::unordered_map 还是 std::unordered_multimap 取决于数据结构的要求和性能考虑。如果需要有序访问和唯一键,可以选择 std::map;如果需要快速查找,并且键可以重复,可以选择 std::unordered_multimap

  • 相关阅读:
    大功率电源的应用场景有哪些(高压功率放大器)
    linux上gitlab备份与还原
    设计模式详解(十七)——迭代子模式
    “医药分离”大背景下,连锁药店如何加速扩张
    糟了,生产环境数据竟然不一致,人麻了!
    基于Python的二次元头像生成器 课程报告+源码
    16、window11+visual studio 2022+cuda+ffmpeg进行拉流和解码(RTX3050)
    计算机毕业设计源代码java项目开发实例ssm+mysql实现简单的物流快递管理系统[包运行成功]
    一款清理本地仓库jar包的maven插件
    sqlalchemy expire_all 方法详解,强制刷新会话缓存
  • 原文地址:https://blog.csdn.net/m0_73731708/article/details/132866216