浅谈C++|STL之map篇

news2024/11/30 14:49:02

在这里插入图片描述

一.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 <iostream>
#include <utility>

int main() {
    std::pair<int, std::string> myPair(1, "Hello");
    std::cout << myPair.first << " " << myPair.second << std::endl;

    return 0;
}

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

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

创建方式

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

  1. 使用构造函数:

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

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

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

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

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

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

1.3map的构造和赋值

map数据类型只能是各种pair

  1. 默认构造函数:

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

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

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

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

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

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

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

构造/赋值方式示例代码
默认构造函数std::map<KeyType, ValueType> myMap;
初始化列表构造函数std::map<KeyType, ValueType> myMap = { {key1, value1}, {key2, value2}, ... };
范围构造函数std::map<KeyType, ValueType> myMap(otherContainer.begin(), otherContainer.end());
拷贝构造函数std::map<KeyType, ValueType> myMap(otherMap);
赋值运算符std::map<KeyType, ValueType> myMap; myMap = otherMap;
移动构造函数std::map<KeyType, ValueType> 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();
    
  2. 判断是否为空:

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

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

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

操作示例代码
获取大小std::map<KeyType, ValueType> myMap;
int size = myMap.size();
判断是否为空std::map<KeyType, ValueType> myMap;
bool isEmpty = myMap.empty();
交换 mapstd::map<KeyType, ValueType> map1;
std::map<KeyType, ValueType> 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());
    
  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());
    
  3. 清空 map:

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

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

操作示例代码
插入单个元素std::map<KeyType, ValueType> myMap;
myMap.insert(std::make_pair(key, value));
插入多个元素std::map<KeyType, ValueType> myMap;
std::map<KeyType, ValueType> anotherMap;
myMap.insert(anotherMap.begin(), anotherMap.end());
删除指定键的元素std::map<KeyType, ValueType> myMap;
myMap.erase(key);
删除迭代器指向的元素std::map<KeyType, ValueType> myMap;
std::map<KeyType, ValueType>::iterator it = myMap.find(key);
if (it != myMap.end()) { myMap.erase(it); }
删除元素范围std::map<KeyType, ValueType> myMap;
myMap.erase(myMap.begin(), myMap.end());
清空 mapstd::map<KeyType, ValueType> 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()) {
        // 元素找到
    }
    
  2. 统计元素个数:

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

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

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

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

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

1.7map容器排序

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

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

#include <iostream>
#include <map>
#include <functional>

// 自定义比较函数,按照值的降序进行排序
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;
}

在示例代码中,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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1007763.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

富斯I6刷10通道固件

使用USB转串口模块刷写10通道固件 一、下载固件 1. 十通道英文固件 下载地址: https://github.com/benb0jangles/FlySky-i6-Mod-/tree/master 选择 FlySky-i6-Mod–master \ 10ch Mod i6 Updater \ 10ch_MOD_i6_Programmer_V1 路径下的文件,亲测可用。 2. 原版六通道中…

[Linux]进程间通信--管道

[Linux]进程间通信–管道 文章目录 [Linux]进程间通信--管道进程间通信的目的实现进程间通信的原理匿名管道匿名管道的通信原理系统接口管道特性管道的协同场景管道的大小 命名管道使用指令创建命名管道使用系统调用创建命名管道 进程间通信的目的 数据传输&#xff1a;一个进…

JL-A/41 JL-A/42 JL-A/43 集成电路电流继电器 过负荷或短路 JOSEF约瑟

JL-A、B集成电路电流继电器 JL-A/11 JL-A/31 JL-A/12 JL-A/32 JL-A/13 JL-A/33 JL-A/21 JL-A/22 JL-A/23 JL-A/34 JL-A/35 JL-B/41 JL-A/42 JL-B/43 JL-B/11 JL-B/31 JL-B/12 JL-B/32 JL-B/13 JL-B/33 JL-B/21 JL-B/22 JL-B/23 JL-B/34 JL-B/35 JL-B/41 JL-B/42 …

Android性能优化之应用瘦身(APK瘦身)

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览2.1 apk组成 三、优化方向3.1 源代码3.1.1 代码混…

bootstrap-datepicker实现只能选择每一年的某一个月份

1、问题描述 最近碰到一个需求&#xff0c;要求日期控件选择的时候&#xff0c;只能选择某一年的1月份。 2、解决方法 使用setStartDate()和setEndDate()函数对日期选择框进行范围限制。 3、我的代码 【免费】bootstrap-datepicker实现只能选择每一年的某一个月份资源-CSDN文库…

JavaWeb_LeadNews_Day12-jenkins

JavaWeb_LeadNews_Day12-jenkins 后端项目部署多环境配置切换服务集成docker配置父工程项目构建构建微服务部署服务到远程服务器整体思路安装私有仓库jenkins插件部署服务准备工作部署服务 jenkins触发器来源Gitee 后端项目部署 多环境配置切换 在微服务中的bootstrap.yml中新…

Dajngo06_Template模板

Dajngo06_Template模板 6.1 Template模板概述 模板引擎是一种可以让开发者把服务端数据填充到html网页中完成渲染效果的技术 静态网页&#xff1a;页面上的数据都是写死的&#xff0c;万年不变 动态网页&#xff1a;页面上的数据是从后端动态获取的&#xff08;后端获取数据库…

二叉树详解(求二叉树的结点个数、深度、第k层的个数、遍历等)

二叉树&#xff0c;是一种特殊的树&#xff0c;特点是树的度小于等于2&#xff08;树的度是整个树的结点的度的最大值&#xff09;&#xff0c;由于该特性&#xff0c;构建二叉树的结点只有三个成员&#xff0c;结点的值和指向结点左、右子树的指针。 typedef int DateType; t…

长亭雷池社区版本安装与使用

0x01 雷池介绍 一款足够简单、足够好用、足够强的免费 WAF。基于业界领先的语义引擎检测技术&#xff0c;作为反向代理接入&#xff0c;保护你的网站不受黑客攻击。核心检测能力由智能语义分析算法驱动&#xff0c;专为社区而生&#xff0c;不让黑客越雷池半步。 官方网址&…

第一类曲线积分与二重积分在极坐标系下表示的区别

1.第一类曲线积分与二重积分在极坐标系下表示的区别 区别主要来源于一是曲线积分的积分区域为边界&#xff0c;而二重积分的积分区域为内部边界&#xff0c;二是极点位置选取的不同&#xff0c;二者共同造成在积分区域在极坐标下表示的不同&#xff0c;即 ρ \rho ρ是常量还是…

解决谷歌浏览器会http网站自动变成https的问题

不知道是不是升级的缘故&#xff0c;最近打开公司一个http网站&#xff0c;会自动跳去https&#xff0c;用了网上说的这个方案&#xff0c;如下&#xff1a; 但发现还不行&#xff0c;这时我尝试用点击地址栏左边那锁的那个图标&#xff0c;图如下&#xff1a; 然后点击网站设…

Pytest系列-数据驱动@pytest.mark.parametrize(7)

简介 unittest 和 pytest参数化对比&#xff1a; pytest与unittest的一个重要区别就是参数化&#xff0c;unittest框架使用的第三方库ddt来参数化的 而pytest框架&#xff1a; 前置/后置处理函数fixture&#xff0c;它有个参数params专门与request结合使用来传递参数&#x…

【javaSE】 枚举与枚举的使用

文章目录 &#x1f384;枚举的背景及定义⚾枚举特性总结&#xff1a; &#x1f332;枚举的使用&#x1f6a9;switch语句&#x1f6a9;常用方法&#x1f4cc;示例一&#x1f4cc;示例二 &#x1f38d;枚举优点缺点&#x1f334;枚举和反射&#x1f6a9;枚举是否可以通过反射&…

【基本数据结构 三】线性数据结构:栈

学习了数组和链表后,再来看看第三种线性表结构,也就是栈,栈和后边讲的队列一样是一种受限的线性表结构,正是因为其使用有限制,所以对于一些特定的需要操作可控的场合,受限的结构就非常有用。 栈的定义 我们平时放盘子的时候,都是从下往上一个一个放;取的时候,我们也…

矩阵系统全方位管理多平台1000多个账号,实现精准化运营获客!

全自动化视频综合处理工具&#xff01; ​ 普通的剪辑软件是不可能实现自动化&#xff0c;一个人一天制作3000条视频&#xff01;​必须要借助高效率的工具【呆头鹅批量剪辑软件】探店混剪系统&#xff0c;导入大量的素材&#xff0c;就能自动帮你批量处理&#xff0c;满…

第28章_瑞萨MCU零基础入门系列教程之基于面向对象的工程结构

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

Django05_反向解析

Django05_反向解析 5.1 反向解析概述 随着功能的不断扩展&#xff0c;路由层的 url 发生变化&#xff0c;就需要去更改对应的视图层和模板层的 url&#xff0c;非常麻烦&#xff0c;不便维护。这个时候我们可以通过反向解析&#xff0c;将 url解析成对应的 试图函数 通过 path…

OSCP系列靶场-Esay-Vegeta1保姆级

OSCP系列靶场-Esay-Vegeta1保姆级 目录 OSCP系列靶场-Esay-Vegeta1保姆级总结准备工作信息收集-端口扫描目标开放端口收集目标端口对应服务探测 信息收集-端口测试22-SSH端口的信息收集22-SSH端口版本信息与MSF利用22-SSH协议支持的登录方式22-SSH手动登录尝试(无)22-SSH弱口令…

魔众携手ModStart上线全新模块市场,支持模板主题

ModStart模板主题 对于很多新手或者是缺乏经验的开发者来说&#xff0c;快速建站具有一定的难度&#xff0c;总是一件让人头疼的问题。 ModStart为开发者提供了一些模板主题供开发者选购使用&#xff0c;模块市场包含了丰富的模块&#xff0c;后台一键快速安装&#xff0c;让开…

Botowski:SEO友好的AI内容生成器

【产品介绍】 名称 Botowski 具体描述 Botowski是一个人工智能内容生成器&#xff0c;可以被撰稿人、企业主和其他人用来创建高质量的内容。 它可以创建各种主题的文章、博客文章&#xff0c;甚至散文。Botowski的设计是用户友好的;你所需要做…