首页 > 编程语言 >C++ STL常用容器之map(关联容器)

C++ STL常用容器之map(关联容器)

时间:2024-07-22 09:27:08浏览次数:13  
标签:std 容器 jeff STL map 红黑树 main

文章目录


前言

本文主要介绍C++ STL常用容器之map(关联容器)的相关概念以及用法。


一、map的介绍

std::map 是C++标准模板库(STL)中的一个关联容器,它包含不重复的键值对(key-value pairs)集合,其中每个键都是唯一的。map的内部使用一个红黑树进行存储,因此能够保持元素的有序性,并提供高效的查找、插入和删除操作。

1.1 使用map的优点

优点描述
快速查找由于map的内部使用红黑树作为数据结构,因此查找、插入和删除操作的时间复杂度为对数级别,非常高效。
唯一性保证map 保证每个键在容器中都是唯一的,不会出现重复键。
支持复杂数据类型map的键和值可以是任意数据类型,包括自定义类型。
动态调整插入和删除操作会自动调整内部结构以保持有序性和平衡性。

1.2 使用map的缺点

缺点描述
空间开销较大由于map的内部使用红黑树来维护元素的有序性和唯一性,因此需要额外的空间来存储树的节点信息。
性能开销插入和删除操作的时间复杂度为 O(log n),对于某些高性能要求的应用来说,可能不如哈希表(如 unordered_map)高效。

1.3 使用场景

map常用于需要快速根据键来查找、插入或删除值的情况。例如:

使用场景描述
有序存储当需要按键的顺序进行遍历或查找时,map 是理想的选择。例如,存储需要按日期排序的日志记录。
快速查找需要在大量数据中快速查找某个键对应的值时,map 可以提供高效的查找能力。
键值对存储需要存储一些关联关系的数据,如学生 ID 和学生信息的关联、单词和其出现频率的关联等。
唯一键要求需要确保每个键是唯一的场景,如用户 ID 映射到用户信息的存储。

二、map常用的操作

2.1 创建、初始化以及遍历容器

#include <iostream>
#include <map>

int main(int argc, char* argv[])
{
	// 使用默认构造函数创建一个空的map
	std::map<int, std::string> myMap;

    // 使用列表初始化创建并初始化map
	std::map<int, std::string> myMap2 = {{1, "one"}, {2, "two"}, {3, "three"}};

	// 使用auto遍历
	for (const auto &pair : myMap2) {
		std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
	}

	// 使用迭代器遍历
    // for (std::map<int, std::string>::iterator it = myMap2.begin(); it != myMap2.end(); it++) {
    //     std::cout << "Key: " << it->first << ", Value: " << it->second << std::endl;
    // }

	return 0;
}

编译后输出如下

jeff@jeff:/tmp$ g++ -o main main.cpp
jeff@jeff:/tmp$ ./main
Key: 1, Value: one
Key: 2, Value: two
Key: 3, Value: three
jeff@jeff:/tmp$

2.2 查询容器大小

#include <iostream>
#include <map>

int main(int argc, char* argv[])
{
	// 使用默认构造函数创建一个空的map
	std::map<int, std::string> myMap;
	std::cout << "myMap.size:" << myMap.size() << std::endl;

    // 使用列表初始化创建并初始化map
	std::map<int, std::string> myMap2 = {{1, "one"}, {2, "two"}, {3, "three"}};
	std::cout << "myMap2.size:" << myMap2.size() << std::endl;

	return 0;
}

编译后输出如下

jeff@jeff:/tmp$ g++ -o main main.cpp
jeff@jeff:/tmp$ ./main
myMap.size:0
myMap2.size:3
jeff@jeff:/tmp$

2.3 访问容器中的元素

#include <iostream>
#include <map>

int main(int argc, char* argv[])
{
	// 使用列表初始化创建并初始化map
	std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};

    // 使用 at() 访问
    std::cout << "Key 1: " << myMap.at(1) << std::endl;

    // 使用 [] 操作符
    std::cout << "Key 2: " << myMap[2] << std::endl;

    // 使用 find()
    auto it = myMap.find(3);
    if (it != myMap.end()) {
        std::cout << "Key 3: " << it->second << std::endl;
    }

	return 0;
}

编译后输出如下

jeff@jeff:/tmp$ g++ -o main main.cpp
jeff@jeff:/tmp$ ./main
Key 1: one
Key 2: two
Key 3: three
jeff@jeff:/tmp$

2.4 往容器中添加元素

#include <iostream>
#include <map>

int main(int argc, char* argv[])
{
	// 使用列表初始化创建并初始化map
	std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};

    // 使用 insert()
    myMap.insert(std::make_pair(4, "four"));

    // 使用 [] 操作符
    myMap[5] = "five";

    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

	return 0;
}

编译后输出如下

jeff@jeff:/tmp$ g++ -o main main.cpp
jeff@jeff:/tmp$ ./main
1: one
2: two
3: three
4: four
5: five
jeff@jeff:/tmp$

2.5 删除容器中的元素

#include <iostream>
#include <map>

int main(int argc, char* argv[])
{
	// 使用列表初始化创建并初始化map
	std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}, {4, "four"}, {5, "five"}};

	std::cout << "before erase" << std::endl;
    for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

	// 通过键删除元素
	myMap.erase(1);

	// 通过迭代器删除元素
	auto it = myMap.find(4);
	if (it != myMap.end()) {
		myMap.erase(it);

	std::cout << "after erase" << std::endl;	}
	for (const auto& pair : myMap) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

	return 0;
}

编译后输出如下

jeff@jeff:/tmp$ ./main
before erase
1: one
2: two
3: three
4: four
5: five
after erase
2: two
3: three
5: five
jeff@jeff:/tmp$

2.6 清空容器中的元素

std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}, {3, "three"}};

// 清空容器
myMap.clear();
std::cout << "Size after clearing: " << myMap.size() << std::endl;

三、扩展

3.1 红黑树的概念

std::map 在C++ STL(标准模板库)中的底层实现通常依赖于红黑树(Red-Black Tree)这种数据结构。红黑树是一种特殊的自平衡二叉搜索树,它通过颜色和一系列的调整规则来保持树的平衡性,从而保证了高效的查找、插入和删除操作。

3.2 红黑树的主要特性

3.2.1 自平衡

红黑树通过颜色(红色或黑色)和一系列旋转操作来维持树的平衡,确保在最坏情况下查找、插入和删除操作的时间复杂度为O(log n),其中n是树中节点的数量。

3.2.1 颜色规则

  1. 每个节点要么是红色,要么是黑色。
  2. 根节点是黑色的。
  3. 每个叶子节点(NIL或空节点)都是黑色的。
  4. 如果一个节点是红色的,则它的两个子节点都是黑色的(即不存在两个红色节点相邻的情况)。
  5. 从任一节点到其每个叶子节点的所有路径都包含相同数量的黑色节点。

3.3 红黑树在std::map中的应用

  1. std::map是一个基于红黑树的关联容器,它存储键值对,并根据键进行排序。
  2. 由于红黑树的自平衡特性,std::map在插入、删除和查找操作时能够保持相对稳定的性能。
  3. std::map中的元素总是按键的升序排列,这是因为红黑树本身就是一种有序的树结构。

3.4 为什么要使用红黑树?

  1. 红黑树相对于其他二叉搜索树(如AVL树)来说,其平衡性要求较低,因此插入和删除操作的旋转次数相对较少,从而提高了效率。
  2. 红黑树在保持平衡的同时,还能保证查找、插入和删除操作的时间复杂度为O(log n),这使得它在处理大量数据时非常高效。

总的来说,红黑树在std::map中的应用为C++程序员提供了一种高效、有序且稳定的键值对存储方式。

标签:std,容器,jeff,STL,map,红黑树,main
From: https://blog.csdn.net/Mr_Jaychong/article/details/140301580

相关文章

  • C++标准模板(STL)- 概念库 (C++20) - 指定一个类型派生自另一类型 - (std::derived_from)
    概念库提供基础语言概念的定义,它们能用于进行模板实参的编译时校验,以及基于类型属性的函数派发。这些概念在程序中提供等式推理的基础。标准库中的大多数概念一同加上了语法及语义要求。通常,编译器只能检查语法要求。若在使用点语义要求未得到满足,则程序为病式,不要求诊断。......
  • SQL server基于报错的注入(使用sqlmap进行get shell)
    SQLserver基于报错的注入1.访问MSSQLSQLiLabs网站点击按钮,我们使用GET请求上传参数“id”,当id=1时,页面显示id=1的用户名Dump、密码Dump:2.寻找注入点http://[靶机IP]/less-1.asp?id=1'运行后报错,说明我们可以利用参数“id”作为我们的注入点,根据回显我们可以判断这是字......
  • MapReduce执行流程
    执行流程MapTask执行流程Read:读取阶段MapTask会调用InputFormat中的getSplits方法来对文件进行切片切片之后,针对每一个Split,产生一个RecordReader流用于读取数据数据是以Key-Value形式来产生,交给map方法来处理。每一个键值对触发调用一次map方法Map:映射阶段map方法在获......
  • JVM 中的OopMap与安全点
    OopMap在JVM中,垃圾回收器需要知道哪些内存位置包含对象引用,以便在垃圾回收过程中正确地处理对象引用和避免回收错误。OopMap(Object-OffsetMap)是一个数据结构,帮助垃圾回收器识别和跟踪对象引用的位置。它在垃圾回收过程中扮演了至关重要的角色。OopMap的工作原理......
  • 【Docker】Docker-consul容器服务自动发现与注册
    目录一.Consul概述1.解决了什么问题2.什么叫微服务或者注册与发现3.consul的模式4.相关命令二.consul部署1.consul服务器部署2.部署docker容器3.Nginx负载均衡器3.1.安装启动nginx3.2.配置nginx负载均衡3.3.创建配置consulcomplate模板文件3.4.添加consul节点3......
  • Chapter 11 Paython数据容器:序列
    欢迎大家订阅【Python从入门到精通】专栏,一起探索Python的无限可能!文章目录前言一、序列的定义二、序列的切片前言在Python中,数据容器是组织和管理数据的重要工具,序列作为其中一种基本的数据结构,具有独特的特性和广泛的应用。本章详细介绍了序列的定义及其切片......
  • 为何你还在坚持用数组?容器不比它香几条街?「上」
    以下内容为本人的烂笔头,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/tm2OKiLBQL2GBCd2ho6i5AC/C++到了寿终正寝的时候否?最近被热议的「美国白宫提倡软件开发者放弃使用C/C++这种语言再进行新的软件开发」。作为一名热衷于高性能架构开......
  • 云原生:容器技术全解!
    一、什么是容器?容器是一种自包含、轻量级、可移植的软件打包技术,它使得应用程序可以在几乎任何地方以相同的方式运行。开发人员在自己笔记本上创建并测试好的容器,无须任何修改就能够在生产系统的虚拟机、物理服务器或公有云上运行。所谓的“自包含”是指容器镜像中完整的......
  • 动态规划-1:穷举遍历->map缓存->取消递归
    importjava.util.HashMap;importjava.util.Map;publicclassDynamicProgrammingAlgorithm{publicstaticvoidmain(String[]args){//比如要求一个数组的最长递增子序列的长度//比如是[1,4,2,5,3],那么[1,2,5],或者[1,2,3]都是最长递增子序......
  • python 舰队容器
    我正在尝试使用容器在flet中制作一个菜单,它应该是半透明的,但其中的项目不是。我尝试将opacity=1分配给元素,但没有成功-它们与容器一样透明感谢任何帮助我的代码:nickname=ft.TextField(label="xxx",hint_text="xxx")column=ft.Column(controls=[nickname......