第四章:树形结构的关联式容器(map+set)

2023-11-19

系列文章目录



前言

根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。


1、关联式容器与序列式容器

vector、list、deque、forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。

而关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高。 (插入删除只需挪动指针指向,无需挪动数据,查找时间logN)

关联式容器有两种,一种是map、set、multimap、multiset采用树形结构,他们的底层都是红黑树,另一种是哈希结构。

1.1 键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息。比如:现在要建立一个英汉互译的字典,那该字典中必然有英文单词与其对应的中文含义,而且,英文单词与其中文含义是一一对应的关系,即通过该应该单词,在词典中就可以找到与其对应的中文含义。

SGI-STL中关于键值对的定义:

template <class T1, class T2>
struct pair
{
  typedef T1 first_type;
  typedef T2 second_type;
  T1 first;
  T2 second;
  pair(): first(T1()), second(T2())
  {}
  pair(const T1& a, const T2& b): first(a), second(b)
  {}
};

2、set的介绍

在这里插入图片描述

  1. set是关联式容器,它表面上只存放value,实际底层中存放的是由<value,value>组成的键值对。

  2. set中的元素不可以重复(因此可以使用set进行去重)。

  3. 使用set的迭代器遍历set中的元素,可以得到有序序列(排序+去重)。

  4. 为了保证元素的唯一性,set中的元素均为const,所以并不能对元素进行修改,但可以进行插入删除。

  5. set中的底层使用二叉搜索树(红黑树)来实现。

  6. set调用find将采用中序遍历。

void test1()
{
	set<int> s1;
	s1.insert(3);
	s1.insert(1);
	s1.insert(2);
	s1.insert(4);
	s1.insert(3);
	s1.insert(5);

	for (auto e : s1)
	{
		cout << e << " ";
	}
	cout << endl;
}
//结果
1 2 3 4 5

3、multiset的介绍

在这里插入图片描述

与set的区别为 :允许键值冗余。

使用multiset的迭代器遍历multiset中的元素,可以得到有序非去重序列(排序)。

void test1()
{
	multiset<int> s2;
	s2.insert(3);
	s2.insert(1);
	s2.insert(2);
	s2.insert(4);
	s2.insert(3);
	s2.insert(5);

	for (auto e : s2)
	{
		cout << e << " ";
	}
	cout << endl;
}

//结果
1 2 3 3 4 5

3.1 接口count与容器multiset

set的count和find的作用一样,都是用于查找set中是否存在某个元素。

其实count是为了容器multiset设计的,该容器允许插入重复的元素,此时count会返回红黑树中被搜索元素的个数。

void test1()
{
	multiset<int> s1;
	s2.insert(3);
	s2.insert(1);
	s2.insert(2);
	s2.insert(4);
	s2.insert(3);
	s2.insert(5);

cout << s1.count(3) << endl;
}

//结果
2

4、map的介绍

在这里插入图片描述

map是关联式容器,根据特定的存储顺序,用于存储由键值及其映射值组合的元素。

可以看到Alloc中有一个键值对pair,这个pair是一个key/value结构的struct模板类。这个类将一对键值耦合在一起,所以,map的存储方式是通过在搜索二叉树中存储键值对pair,而搜索二叉树的k/v模型是在节点中存储key和value,并不相同。pair的结构:

在这里插入图片描述

template <class T1, class T2>
struct pair
{
	typedef T1 first_type;
	typedef T2 second_type;
	T1 first;
	T2 second;
	pair(): first(T1()), second(T2())
	{}
	pair(const T1& a, const T2& b): first(a), second(b)
	{}
};

4.1 接口insert

在这里插入图片描述

使用map的迭代器遍历map中的元素,可以得到有序序列(排序+去重)。

void test2()
{
	map<string, string> dict;
	dict.insert(pair<string, string>("left", "左边"));
	dict.insert(pair<string, string>("right", "右边"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("count", "计数"));
	dict.insert(make_pair("count", "计数"));
    
	
	map<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
}
//结果
count:计数
left:左边
right:右边
sort:排序
string:字符串

make_pair是一个函数模板:

在这里插入图片描述

template <class T1,class T2>
pair<T1,T2> make_pair (T1 x, T2 y)
{
	return ( pair<T1,T2>(x,y) );
}

为了保证元素的唯一性,map中的元素均为const,所以并不能对元素进行修改,但可以进行插入删除。

4.2 operator[]和at

使用map统计每个字符出现个数

void test3()
{
	string arr[] = { "西瓜", "西瓜", "苹果", "苹果", "香蕉", "梨" };

	map<string, int> countMap;
	for (auto& e : arr)
	{
		auto ret = countMap.find(e);
		if (ret == countMap.end())
		{
			countMap.insert(make_pair(e, 1));
		}
		else
		{
			ret->second++;
		}
	}

	for (auto e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
}

调用insert函数,函数的第二个参数为value类型的缺省值,调用默认构造。

返回值是pair<iterator,bool>,pair.first 表示迭代器 ,解引用就为pair数据 ,pair数据取second就为value。

void test4()
{
	string arr[] = { "西瓜", "西瓜", "苹果", "苹果", "香蕉", "梨" };

	map<string, int> countMap;
	for (auto& e : arr)
	{
		countMap[e]++;
	}

	for (auto e : countMap)
	{
		cout << e.first << ":" << e.second << endl;
	}
}
V& operator[](const K& key)
{
  pair<iterator, bool> ret = insert(make_pair(key, V()));
  return ret.first->second;
}

在这里插入图片描述

【operator[]的作用】:

  1. 插入:插入 left,第二个给缺省值,而string缺省值为空串。

  2. 修改:由于插入的left已经存在,所以插入失败,并寻找之前已经存在的left对应的迭代器,把left迭代器的返回值 value修改为左边。

  3. 插入+修改:插入right,第二个缺省值为空串,并把返回值 value修改为右边。

  4. 查找:直接返回对应的value值即可。

5、multimap的介绍

在这里插入图片描述

与map的区别:允许键值冗余。

使用multimap的迭代器遍历multiset中的元素,可以得到有序非去重序列(排序)。

void test5()
{
	multimap<string, string> dict;
	dict.insert(pair<string, string>("left", "左边"));
	dict.insert(pair<string, string>("right", "右边"));
	dict.insert(make_pair("sort", "排序"));
	dict.insert(make_pair("string", "字符串"));
	dict.insert(make_pair("count", "计数"));
	dict.insert(make_pair("count", "数字"));


	multimap<string, string>::iterator it = dict.begin();
	while (it != dict.end())
	{
		cout << it->first << ":" << it->second << endl;
		++it;
	}
}
//结果
count:计数
count:数字
left:左边
right:右边
sort:排序
string:字符串

但是multimap并没有operator[],因为在map中,key和value是一对一的关系,在multimap中,key和value是一对多的关系,所以没办法判断当前key值对应哪一个value。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第四章:树形结构的关联式容器(map+set) 的相关文章

  • 使用 gcc 在 Linux 上运行线程构建块 (Intel TBB)

    我正在尝试为线程构建块构建一些测试 不幸的是 我无法配置 tbb 库 链接器找不到库 tbb 我尝试在 bin 目录中运行脚本 但这没有帮助 我什至尝试将库文件移动到 usr local lib 但这又失败了 任何的意见都将会有帮助 确定您
  • 结构化绑定中缺少类型信息

    我刚刚了解了 C 中的结构化绑定 但有一件事我不喜欢 auto x y some func is that auto正在隐藏类型x and y 我得抬头看看some func的声明来了解类型x and y 或者 我可以写 T1 x T2 y
  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 需要帮助优化算法 - 两百万以下所有素数的总和

    我正在尝试做一个欧拉计划 http projecteuler net问题 我正在寻找 2 000 000 以下所有素数的总和 这就是我所拥有的 int main int argc char argv unsigned long int su
  • 如何定义一个可结构化绑定的对象的概念?

    我想定义一个concept可以检测类型是否T can be 结构化绑定 or not template
  • 为什么使用小于 32 位的整数?

    我总是喜欢使用最小尺寸的变量 这样效果就很好 但是如果我使用短字节整数而不是整数 并且内存是 32 位字可寻址 这真的会给我带来好处吗 编译器是否会做一些事情来增强内存使用 对于局部变量 它可能没有多大意义 但是在具有数千甚至数百万项的结构
  • 如何实例化 ODataQueryOptions

    我有一个工作 简化 ODataController用下面的方法 public class MyTypeController ODataController HttpGet EnableQuery ODataRoute myTypes pub
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • 为什么 std::uint32_t 与 uint32_t 不同?

    我对 C 有点陌生 我有一个编码作业 很多文件已经完成 但我注意到 VS2012 似乎有以下语句的问题 typedef std uint32 t identifier 不过 似乎将其更改为 typedef uint32 t identifi
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • android常用框架!万字长文轻松彻底入门Flutter,使用指南

    前言 说不焦虑其实是假的 因为无论是现在还是最近几年 很早就有人察觉Android开发的野蛮生长时代已经过去 过去的优势是市场需要 这个技术少有人有 所以在抢占市场的时候 基本上满足需要就已经可以了 但是现在 各式各样的APP层出不穷 AP
  • python类

    python是一种面向对象的变成语言 python几乎所有的东西都是对象 包括对象和属性 一 类的定义 python类的定义 class ClassName pass 实例 注意 类中的函数称为方法 有关于函数的一切适用于方法 唯一的区别在
  • MySQL出现“Lost connection to MySQL server during query”问题分析与解决

    问题重现 有一个表总是在写入数据的时候报2013的错误 原因分析 官方文档 总结一下3种可能性 一般都是第一或第二种原因 首先SQLAlchemy官方对该错误的解释 针对与数据库操作相关的错误而引发的异常 并且不一定在程序员的控制之下 例如
  • BUUCTF [CSAWQual 2019]Web_Unagi 1

    BUUCTF CSAWQual 2019 Web Unagi 1 提示在 flag 有提示了上传xml文件及其格式 直接用之前xml注入的上传即可 改文件名为1 xml上传即可得flag gt
  • 关于如何解决:Maven无法从aliyun仓库自动下载jar包(情况之一)

    如果你出现修改Maven配置文件settings xml无法生效 或者无法从aliyun仓库自动下载jar包的情况 除了其他博主提出的情况与解决方案以外 你如果还没有解决 检查是否遇到以下情况 最首先应当去aliyun官网 https de
  • C++之数据类型

    数据类型可以分为 基本数据类型 和 非基本数据类型 1 基本数据类型 整型 int 布尔值类型 bool 浮点数类型 double 字符类型 char void类型 2 非基本数据类型 指针类型 type 数组类型 type 引用类型 do
  • 1028 人口普查 (20分))(C语言)

    1028 人口普查 20分 某城镇进行人口普查 得到了全体居民的生日 现请你写个程序 找出镇上最年长和最年轻的人 这里确保每个输入的日期都是合法的 但不一定是合理的 假设已知镇上没有超过 200 岁的老人 而今天是 2014 年 9 月 6
  • 计算机修改桌面图标大小,windows更改桌面图标大小设置

    对于windows系统使用 不同的人有不同的使用习惯 有些人不习惯windows桌面的默认图标大小 想更改桌面图标大一些或小一些 小编就遇到一个有高度近视的同事 默认的桌面图标他根本看不清 需要把眼睛贴近显示器才能看清 所以他就需要把图标设
  • koa使用之node.js 文件加密与解密

    利用node js的crypto模块实现文件加密解密 代码 加密函数 param text 需要加密的内容 param key 秘钥 returns Query 密文 function encode text key var secret
  • 解释 RESTful API,以及如何使用它构建 web 应用程序

    RESTful API stands for Representational State Transfer Application Programming Interface It is a set of principles and g
  • uniapp开发app原生子窗体subNvue的使用

    用uniapp开发app的时候经常会有以下问题 1 覆盖原生导航栏 tabbar 的弹出层组件 比如侧滑菜单盖不住地图 视频 原生导航栏 比如 popup盖不住tabbar 2 弹出层内部元素可滚动 3 在map video等组件上的添加复
  • FPGA——按键消抖常用模板代码

    模板如下 define UD 1 module key jitter input clkin input key in output key value output 15 0 tout inner signal reg 1 0 key i
  • Angular1.x 基础入门

    一 Angular1 x概述 致力于单页面应用 single page application 不直接操作DOM元素 数据驱动为核心 以操作数据完成页面的一系列 二 Angular1 x特点 MVC MVC模式 Model 模型 业务数据
  • ts(TypeScript)常用语法(Omit、Pick、Partial、Required)

    ts TypeScript 常用语法 比如有一个联系人列表 export interface Contact name string 姓名 phone string 手机号 email string 邮箱 avatar string 头像
  • appium根据屏幕大小滑动界面driver.get_window_size()、driver.swipe()

    driver get window size 获取屏幕的宽 高 driver swipe 从坐标1滑动到坐标2 t毫秒时间内完成 上下滑动时 坐标的x值可以不变 只改变坐标y值的大小 左右滑动时 坐标的y值可以不变 只改变坐标x值的大小 上
  • 分布式系统与微服务的区别是什么?

    分布式系统和微服务是两个相关但不同的概念 它们都是在构建复杂的软件应用时使用的架构思想 分布式系统 分布式系统是指由多个独立的计算机或服务器通过网络连接共同工作 协同完成一个任务或提供一个服务 在分布式系统中 各个计算机节点可以分担任务的负
  • “华为杯”研究生数学建模竞赛2019年-【华为杯】D题:汽车行驶工况构建(附获奖论文和MATLAB代码实现)

    目录 摘 要 1 问题重述 2 模型假设 2 1 题目对模型给出的假设
  • Qt核心特性之 —— 「信号(Signal)与槽(Slot)」机制

    目录 1 Qt 与 Qt Creator简介 2 关于引用头文件的一些事儿 3 信号 Signal 与槽 Slot 机制 3 1 一个小例子 4 自定义信号与槽 4 1 运行效果 5 信号与槽的特性 6 Qt 4 版本以前 connect
  • linux 如何创建卷组

    1 创建一个物理卷 Pvcreate dev sd1 dev sd2 dev sd3 dev sd4 2 用刚才创建的物理卷创建一个卷组 Vgcreate 卷组名 dev sd1 dev sd2 dev sd3 dev sd4 3 创建逻辑
  • 第四章:树形结构的关联式容器(map+set)

    系列文章目录 文章目录 系列文章目录 前言 1 关联式容器与序列式容器 1 1 键值对 2 set的介绍 3 multiset的介绍 3 1 接口count与容器multiset 4 map的介绍 4 1 接口insert 4 2 oper