STL中的map

news2024/9/20 16:38:08

概述

std::map 是一个模板类,定义在头文件 <map> 中:

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T>>
> class map;
  • std::map 是一种有序关联容器,它包含具有唯一键的键值对。
  • 键之间以比较函数 Compare 排序。
  • 搜索、移除和插入操作拥有对数复杂度。
  • map 通常实现为红黑树。

std::map 的迭代器以升序迭代各键,此升序由构造时所用的比较函数定义。就是说,给定

  • m,一个 std::map
  • it_lit_rm 的可解引用迭代器,且 it_l < it_r

m.value_comp()(*it_l, *it_r) == true(使用默认比较函数时为从小到大排序)。

标准库使用比较概念时,均用等价关系来确定唯一性。不精确地说,如果两个对象 ab 相互比较均不小于对方:!comp(a, b) && !comp(b, a),那么认为它们等价。

map中的成员类

在这里插入图片描述

map类中的成员函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

map类中的非成员函数

在这里插入图片描述

成员函数begin与cbegin

std::map<Key,T,Compare,Allocator>::begin, std::map<Key,T,Compare,Allocator>::cbegin

函数原型:
在这里插入图片描述
函数功能:返回指向 map 首元素的迭代器。如果 map 为空,那么返回的迭代器等于 end()

在这里插入图片描述
函数说明:

  • 参数:无参数;
  • 返回值:指向首元素的迭代器;
  • 复杂度:常数:
  • 注解:libc++ 将 cbegin() 向后移植到 C++98 模式。

函数使用示例:

#include <iostream>
#include <map>
 
int main()
{
    std::map<int, float> num_map;
    num_map[4] = 4.13;
    num_map[9] = 9.24;
    num_map[1] = 1.09;
    // 调用 num_map.begin() 和 num_map.end()
    for (auto it = num_map.begin(); it != num_map.end(); ++it)
        std::cout << it->first << ", " << it->second << '\n';
}

输出:

1, 1.09
4, 4.13
9, 9.24

使用自定义比较函数的示例

#include <cmath>
#include <iostream>
#include <map>
 
struct Point { double x, y; };
 
// 比较两个 Point 指针的 x 坐标。
struct PointCmp
{
    bool operator()(const Point* lhs, const Point* rhs) const
    {
        return lhs->x < rhs->x; 
    }
};
 
int main()
{
    // 注意尽管 x 坐标乱序,亦将按照递增的 x 坐标迭代 map。
    Point points[3] = {{2, 0}, {1, 0}, {3, 0}};
 
    // mag 是发送结点地址到其在 x-y 平面中长度的 map
    // 尽管键为指向 Point 的指针,我们希望按照点的 x 坐标而非点的地址为 map 赋序。
    // 通过用 PointCmp 类的比较方法进行。
    std::map<Point*, double, PointCmp> mag(
        {{points, 2}, {points + 1, 1}, {points + 2, 3}}
    );
 
    // 从 0 到长度更改每个 y 坐标
    for (auto iter = mag.begin(); iter != mag.end(); ++iter)
    {
        auto cur = iter->first; // 指向 Node 的指针
        cur->y = mag[cur]; // 亦能用 cur->y = iter->second;
    }
 
    // 更新并打印每个节点的长度。
    for (auto iter = mag.begin(); iter != mag.end(); ++iter)
    {
        auto cur = iter->first;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << iter->second << '\n';
    }
 
    // 以基于范围的 for 循环重复上述内容。
    for (auto i : mag)
    {
        auto cur = i.first;
        cur->y = i.second;
        mag[cur] = std::hypot(cur->x, cur->y);
        std::cout << "The magnitude of (" << cur->x << ", " << cur->y << ") is ";
        std::cout << mag[cur] << '\n';
        // 注意与上述 std::cout << iter->second << '\n'; 相反,
        // std::cout << i.second << '\n'; 将不打印更新的长度。
        // 如果用的是 auto &i : mag,则它会打印更新的长度。
    }
}

输出:

The magnitude of (1, 1) is 1.41421
The magnitude of (2, 2) is 2.82843
The magnitude of (3, 3) is 4.24264
The magnitude of (1, 1.41421) is 1.73205
The magnitude of (2, 2.82843) is 3.4641
The magnitude of (3, 4.24264) is 5.19615

map的初始化方式

  1. 使用赋值和下标运算符初始化
  2. 使用初始化列表初始化
  3. 使用pair数组初始化
  4. 使用 map.isnert() 方法从另一个map初始化
  5. 使用拷贝构造函数从另一个map初始化
  6. 通过范围初始化

1. 使用赋值和下标运算符

最简单的初始化方式就是使用赋值运算符(=)和 下标运算符([]),如下所示:

语法

map<string, string>New_Map;
New_Map[5] =6;  

这里:

  • [] 是下标运算符
  • = 是赋值运算符

如下是实现上述方法的程序:

// C++ program to implement the 
// above approach
#include <iostream>
#include <map>
using namespace std;

// Driver code
int main() 
{
	// Initialize map using 
	// default constructor
	map<string, string>New_Map;

	// Keep on adding key-value pairs 
	// using subscript([]) and 
	// assignment(=) operators
	New_Map["Ground"] = "Grass";
	New_Map["Floor"] = "Cement";
	New_Map["Table"] = "Wood";

	// Traverse through the map
	for(auto x: New_Map)
	{
		cout << x.first << "->" << x.second <<endl;
	}
	return 0;
}

输出

Floor->Cement
Ground->Grass
Table->Wood

时间复杂度: 插入操作 O ( N l o g N ) O(NlogN) O(NlogN),遍历操作 O ( N ) O(N) O(N),其中 N N N 是map中的元素数量
空间复杂度: O ( N ) O(N) O(N) 存储map中的键值对

2. 使用初始化列表

map的另一种初始化方法是使用预定义的键值对列表。

语法:

map<string, string>New_Map = {{key1, value1}, 
                             {key2, value2}, 
                             {key3, value3}}; 

实现上述方法的程序:

// C++ program to implement 
// the above approach
#include <iostream>
#include <map>
using namespace std;

// Driver code
int main() 
{
	// Initialize map using 
	// default constructor
	map<string, string>New_Map;

	// Adding key-value pairs 
	// using Initializer list
	New_Map = {{"Ground", "Grass"}, 
				{"Floor", "Cement"}, 
				{"Table", "Wood"}};
	
	// Traverse through the map
	for(auto x: New_Map)
	{
		cout << x.first << "->" << 
				x.second <<endl;
	}
	
	return 0;
}

输出

Floor->Cement
Ground->Grass
Table->Wood

3. 使用pair数组

map存储键值对,可以使用相同类型的pair数组来存储键值。

语法:

map<string, string> New_map(old_arr, old_arr + n); 

这里,old_arr 是 pair 数组,其中的内容将被复制到 new_map 中。

在 pair 是 vector 的情况下,可以使用内置迭代器将内容从vector复制到新的map中。

map<int, int> New_Map(old_vector.begin(), old_vector.end()); 

这里,old_vector 是一个pair的 vector,其中的内容将复制到 new_map 中。

如下是实现上述方法的程序:

// C++ program to implement
// the above approach
#include <bits/stdc++.h>
using namespace std;

// Driver code
int main() 
{
	// Initialize an array of pair 
	// of strings
	pair<string,string> old_arr[] = 
	{
		make_pair("Ground", "Grass"),
		make_pair("Floor", "Cement"),
		make_pair("Table", "Wood")
	};

	int n = (sizeof(old_arr) / 
				sizeof(old_arr[0]));

	// Add these key-value pairs using 
	// the pairs stored in the array of pairs 
	map<string, string> New_Map(old_arr, old_arr + n);

	// Traverse through the map
	for(auto x: New_Map)
	{
		cout << x.first << "->" << 
				x.second <<endl;
	} 
	
	return 0;
}

输出

Floor->Cement
Ground->Grass
Table->Wood

4. 使用 map.insert()方法从另一个map进行初始化

在C++中,将元素从 现有旧 map 复制到新map 的标准方法是使用 map.insert 成员函数。
语法:

map<string, string> New_Map;
New_Map.insert(old_map.begin(), old_map.end()); 

这里,old_map 中的内容会被复制到 new_map 中。

如下是实现上述方法的程序:

// C++ program to implement 
// the above approach
#include <iostream>
#include <map>
using namespace std;

// Driver code
int main() 
{
	// Initialize an map using 
	// default constructor
	map<string, string>old_map;

	// Adding key-value pairs using 
	// subscript([]) and assignment(=) operators
	old_map["Ground"] = "Grass";
	old_map["Floor"] = "Cement";
	old_map["Table"] = "Wood";


	// Create a new_map where contents 
	// of the previous map will be 
	// copied using copy constructor 
	// and iterator provided by the map 
	map<string, string> New_Map;
	New_Map.insert(old_map.begin(),
					old_map.end());

	// Traverse through the map
	for(auto x: New_Map)
	{
		cout << x.first << "->" << 
				x.second <<endl;
	}
}

输出

Floor->Cement
Ground->Grass
Table->Wood

5. 使用拷贝构造函数从另一个 map 中初始化

初始化 map 的一种方法是使用拷贝构造函数从另一个 map 一个接一个地复制内容。

语法:

map<string, string> New_Map(old_map);

这里,old_map 中的内容会被拷贝到 new_map 中。

如下是实现上述方法的程序:

// C++ program to implement 
// the above approach
#include <iostream>
#include <map>
using namespace std;

// Driver code
int main() 
{
	// Initialize a map using 
	// default constructor
	map<string, string>old_map;

	// Adding key-value pairs using 
	// subscript([]) and assignment(=) 
	// operators
	old_map["Ground"] = "Grass";
	old_map["Floor"] = "Cement";
	old_map["Table"] = "Wood";

	// Create a new_map where contents 
	// of the previous map will be copied 
	// using copy constructor 
	map<string, string>New_Map(old_map);

	// Traverse through the unordered_map
	for(auto x: New_Map)
	{
		cout << x.first << "->" << x.second <<endl;
	} 
	
	return 0;
}

输出

Floor->Cement
Ground->Grass
Table->Wood

6. 通过范围初始化

初始化 map 的另一种方法是通过一系列键值对进行初始化。

语法:

map<string, string> New_Map(old_map.begin(), old_map.end());

在这里,我们不使用另一个map,而是存储任意范围的键值对。

实现上述方法的程序:

// C++ program to implement 
// the above approach
#include <iostream>
#include <map>
using namespace std;

// Driver code
int main() 
{
	// Initialize a map using 
	// default constructor
	map<string,string>old_map;

	// Adding key-value pairs using 
	// subscript([]) and assignment(=) 
	// operators
	old_map["Ground"] = "Grass";
	old_map["Floor"] = "Cement";
	old_map["Table"] = "Wood";

	// Create a new_map where a range 
	// of key-value pairs are stored 
	// from old_map
	map<string, string> New_Map(old_map.begin(), old_map.end());

	// Traverse through the map
	for(auto x: New_Map)
	{
		cout << x.first << "->" << x.second <<endl;
	}
	
	return 0;
}

输出

Floor->Cement
Ground->Grass
Table->Wood

C++ 中通过引用传递map

通过值传递map是一项成本高昂的任务,主要是在计算和内存资源方面代价高。当我们通过值传递 map 时,会创建一个新的 map 副本,时间复杂度 O ( n ) O(n) O(n)。当我们在递归函数中使用 Map时,用值传递就是噩梦。

通过引用传递 map 比通过值传递 map 快得多,而且还能使得我们可以自由地修改函数内的原始map。

&(的地址) 运算符用于传递容器的地址,该地址表示容器在函数中通过引用传递。

例子:

// C++ Program to implement
// Passing Map As Reference
#include <iostream>
#include <map>
using namespace std;

// function that accept map by reference and make changes to
// some of its values
void pass_by_reference(map<int, int>& passed_map)
{
	// change 1st and 3rd value
	passed_map[1] = 200;
	passed_map[3] = 300;
}

// main function
int main()
{
	// empty map container
	map<int, int> gfg;

	// insert elements in map
	gfg[1] = 25;
	gfg[2] = 45;
	gfg[3] = 35;
	gfg[4] = 65;
	gfg[5] = 55;
	gfg[6] = 25;

	// printing original map gfg
	cout << "Original Map\n";
	cout << "\tKEY\tELEMENT\n";
	for (auto i : gfg) {
		cout << '\t' << i.first << '\t' << i.second << '\n';
	}

	// passing map to a function by reference
	pass_by_reference(gfg);

	// printing map gfg after passing it to a function by
	// reference
	cout << "Map After passing to a function by reference\n";
	cout << "\tKEY\tELEMENT\n";
	for (auto i : gfg) {
		cout << '\t' << i.first << '\t' << i.second << '\n';
	}

	return 0;
}

输出

Original Map
    KEY    ELEMENT
    1    25
    2    45
    3    35
    4    65
    5    55
    6    25
Map After passing to a function by reference
    KEY    ELEMENT
    1    200
    2    45
    3    300
    4    65
    5    55
    6    25

解释:

  • 首先定义了一个返回数据类型为 void 的函数,并通过引用获取map<int,int>
  • 通过引用传递参数的这个函数仅仅修改key为1和3的值
  • 之后,在main函数内部,声明一个 map<int,int>
  • 然后,在map中插入一些数据
    -接着,打印我们创建的原始map
    -现在将map传递给通过引用传递参数的函数
  • 最后,打印map

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

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

相关文章

考研C语言刷编程题篇之分支循环结构基础篇(一)

目录 第一题 第二题 方法一&#xff1a;要循环两次&#xff0c;一次求阶乘&#xff0c;一次求和。 注意&#xff1a;在求和时&#xff0c;如果不将sum每次求和的初始值置为1&#xff0c;那么求和就会重复。 方法二&#xff1a; 第三题 方法一&#xff1a;用数组遍历的思想…

redis-exporter grafana面板配置

一、前言 关于使用tensuns自带的grafana监控模板&#xff0c;监控redis-exporter接口会有一些数据丢失的问题&#xff0c;需要自行修改一下grafana模板的json 二、修改模板 redis grafana模板id&#xff1a;17507 主要是针对cpu使用率和内存使用率做一个说明&#xff0c;因为…

mac 中vscode设置root启动

1. 找到你的vscode app&#xff0c;点击鼠标右键------->选项----->在访达中显示 2. 终端中输入以下命令&#xff0c;不要点回车&#xff0c;不要点回车&#xff0c;输入一个空格 sudo chflags uchg 3. 然后将你的程序拖到终端&#xff0c;会自动…

智能光栅光片显微成像技术的LabVIEW解决方案

智能光栅光片显微成像技术的LabVIEW解决方案 在生物医学研究中&#xff0c;高效的成像技术对于捕捉细胞内罕见和复杂事件至关重要。智能光栅光片显微技术&#xff08;smartLLSM&#xff09;的出现&#xff0c;代表了LabVIEW软件在高端成像领域的革命性应用&#xff0c;这项技术…

Mac M1 Parallels CentOS7.9 Deploy Typecho

一、创建名称空间 kubectl create ns prod二、创建PV & PVC vim local-pv1.yamlapiVersion: v1 kind: PersistentVolume metadata:name: local-pv-1 spec:capacity:storage: 1GiaccessModes:- ReadWriteOncepersistentVolumeReclaimPolicy: RetainstorageClassName: loca…

Selenium WebDriver与RC的差异

什么是Selenium WebDriver&#xff1f; Selenium WebDriver 是用于测试Web应用程序的API的开源集合。Selenium WebDriver工具&#xff0c;它还允许执行跨浏览器测试。 WebDriver还能够使用编程语言在创建测试脚本时使用。现在可以使用条件运算就像If-Then-Else或Switch-Case。…

Centos 7 单机部署 consul

一、下载安装 参考官网文档 Install | Consul | HashiCorp Developer 进入Centos 执行下面命令 sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo sudo yum -y install consul 这种方法安装完成…

linux下vsc的自动切换输入法解决方案

前言 个人使用的是Linux开发加上vsc编辑器&#xff0c;这两个东西一加中国开发者大致上就消失不见了&#xff0c;眼馋idea那个Smartinput很久了&#xff0c;赶上放假了&#xff0c;有空搞搞&#xff0c;如果后期有心情会做的通用点 安装 商店搜索SmartInputLinux安装 使用…

STM32标准库开发—MPU6050详细介绍

MPU6050简介 3轴IMU即只有3轴陀螺仪的IMU&#xff0c;其因为只有一个3轴陀螺仪&#xff0c;所以只能感知载体roll&#xff08;滚转&#xff09;、pitch&#xff08;俯仰&#xff09;、yawl&#xff08;偏航&#xff09;共3个自由度的姿态信息。 6轴IMU在3轴IMU的基础上加装了3轴…

Unity之射线检测

不知道大家有没有玩过红色警戒 —— 一款即时战略游戏&#xff0c;和罪恶都市一样小编小学的时候就开始玩了&#xff0c;这款游戏控制单位角色移动是通过鼠标的点击来实现。 同样的操作方法还有英雄联盟等很多游戏&#xff0c;那本篇文章小编就通过简单小实例来讲解这种操作在U…

[ComfyUI进阶教程] lcm+Lora+Controlnet工作流工作流

这是一个使用了LCMlora加载器CN&#xff08;depthtile&#xff09;的工作流。 工作流特性&#xff1a; LCM lora加载器&#xff0c;加快生成图片的时间。 配置了3个lora加载器&#xff0c;用来进行人物和风格设定。 提示词编辑器&#xff0c;预制了默认的动态提示词。 使用了…

linux第一个小程序 --- 进度条【简洁】

行缓冲区的概念 结果&#xff1a;先输入hello world然后休眠三秒后结束 当去掉’\n“ 后&#xff0c;结果就变成了先休眠三秒&#xff0c;然后打印hello world后结束。 该现象就证明了缓冲区的存在。 当缓冲区中遇到’‘\n’或者缓冲区被写满后才会被打印出来&#xff0c;在第…

【设计模式】腾讯二面:自动贩卖机/音频播放器使用了什么设计模式?

状态模式是什么&#xff1f; 状态模式&#xff0c;也被称作状态对象模式&#xff0c;是一种行为设计模式。 当一个对象的内在状态改变时&#xff0c;允许改变其行为&#xff0c;这个对象看起来像是改变了其类。 它让对象在其内部状态改变时改变自己的行为。外部调用者无需了…

(蓝桥杯每日一题)love

问题描述 马上就要到七夕情人节了&#xff0c;小蓝在这天想要心爱得男神表白&#xff0c;于是她写下了一个长度为n仅由小写字母组成的字符串。 她想要使这个字符串有 1314个 love 子序列但是马虎的小蓝却忘记了当前已经有多少个子序列为 love。 请你帮小蓝计算出当前字符串有多…

Rustdesk 中VP8 / VP9 / AV1 是什么?

环境&#xff1a; Rustdesk1.1.9 VP8 / VP9 / AV1 问题描述&#xff1a; VP8 / VP9 / AV1 是什么&#xff1f; 解决方案&#xff1a; 1.VP8、VP9和AV1是视频编解码器&#xff0c;用于压缩和解压缩视频数据。它们是由Google和Alliance for Open Media&#xff08;AOM&#…

spring springfox-swagger2 2.7.0配置

springboot版本 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.0.RELEASE</version><relativePath/> <!-- lookup parent from repository -->…

解决国内Linux服务器无法使用Github的方法

解决思路&#xff1a;修改Host https://www.ipaddress.com/ 利用上面的网站查询github.com和raw.githubusercontent.com的DNS解析的IP地址 最后&#xff0c;修改服务器的/etc/hosts 添加如下两行&#xff1a; 140.82.112.3 github.com 185.199.108.133 raw.githubuserconte…

Python 中多线程与多处理之间的区别

一、说明 在本文中&#xff0c;我们将学习 Python 中多线程和多处理的内容、原因和方式。在我们深入研究代码之前&#xff0c;让我们了解这些术语的含义。 二、基本术语和概念 程序是一个可执行文件&#xff0c;它由一组执行某些任务的指令组成&#xff0c;通常存储在计算机的…

数据恢复轻松搞定:如何处理.adver的数据勒索

引言&#xff1a; 勒索病毒日益猖獗&#xff0c;.adver 勒索病毒作为新兴威胁之一&#xff0c;给用户的数据安全带来了不小的挑战。本文将深入介绍.adver勒索病毒的特点、被加密数据的恢复方法&#xff0c;以及全面的预防措施&#xff0c;帮助您更好地了解并应对这一数字威胁。…

【每日一题】按分隔符拆分字符串

文章目录 Tag题目来源解题思路方法一&#xff1a;遍历方法二&#xff1a;getline 写在最后 Tag 【遍历】【getline】【字符串】【2024-01-20】 题目来源 2788. 按分隔符拆分字符串 解题思路 方法一&#xff1a;遍历 思路 分隔符在字符串开始和结束位置时不需要处理。 分隔…