【C++高阶】高效数据存储:理解并模拟实现红黑树Map与Set

📝个人主页🌹:Eternity._
⏩收录专栏⏪:C++ “ 登神长阶 ”
🤡往期回顾🤡:了解 红黑树
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

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

❀模拟实现Map与Set

  • 📒1. 改造红黑树
  • 📜2. 红黑树的迭代器
    • 🌞迭代器基本设计
    • 🌙begin()与end()
    • ⭐operator++()与operator--()
  • 📚3. Set的模拟实现
    • 🧩Set的基本设计
  • 📝4. Map的模拟实现
    • 🧩Map的基本设计
  • 📖5. 总结


前言: 在编程的浩瀚宇宙中,数据结构作为构建程序的基石,扮演着至关重要的角色。它们不仅定义了数据的存储方式,还极大地影响着程序的性能与效率。在众多经典数据结构中,Map(映射)和Set(集合)以其独特的性质和广泛的应用场景,成为了程序员们手中不可或缺的工具。Map允许我们根据键(Key)快速检索值(Value),而Set则提供了一种不包含重复元素的数据集合

深入理解并熟练掌握这些高级数据结构,并非一蹴而就。为了更加深刻地认识Map与Set的工作原理,以及它们背后隐藏的算法智慧,一个行之有效的方法便是亲手模拟实现它们。这一过程,不仅能够帮助我们加深对数据结构的理解,还能在实践中锻炼编程能力和问题解决能力

本文旨在为读者提供一个全面而深入的视角,通过逐步解析红黑树的基本原理、详细阐述模拟实现的过程,并辅以丰富的代码示例,帮助读者掌握红黑树Map与Set的构建与使用。我们将从最基本的二叉搜索树出发,逐步引入红黑树的特性和规则

让我们一起踏上学习的旅程,探索它带来的无尽可能!


📒1. 改造红黑树

改造红黑树以适配map和set容器,主要涉及到如何根据这两种容器的特性来设计和实现红黑树节点的存储以及相应的操作。map和set的主要区别在于它们存储的元素类型:map存储键值对(key-value pairs),而set仅存储唯一的键值(通常是键本身作为值)。尽管如此,它们在底层数据结构(如红黑树)的实现上有很多相似之处

改造内容:

  • K:key的类型
  • T:如果是map,则为pair<K, V>; 如果是set,则为K
  • KeyOfT:通过T来获取key的一个仿函数类
// Map 与 Set
// set -> RBTree<K, K, SetKeyOfT> _t;
// map -> RBTree<K, pair<const K, V, MapKeyOfT>> _t;

红黑树的节点设计:

enum Color
{RED,BLACK
};template<class T>
struct RBTreeNode
{RBTreeNode<T>* _left;RBTreeNode<T>* _right;RBTreeNode<T>* _parent;// pair<K, V> _kv; // 上节内容使用的这种方式T _data;Color _col;RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _col(RED){}
};

红黑树类的实现参考上一篇文章:红黑树类的实现
与红黑树类的不同的是Insert(插入)的类型是pair<iterator, bool>或者pair<Node*, bool>,然后还要修改内部的return返回的对象
在这里插入图片描述

在这里插入图片描述

以pair<Node*, bool>为例
代码示例:

pair<Node*, bool> Insert(const T& data){if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(_root, true);}Node* parent = nullptr;Node* cur = _root;// 通过仿函数KeyOfT来比较数据的大小KeyOfT kot;while (cur){parent = cur;if (kot(cur->_data) < kot(data)){cur = cur->_right;}else if (kot(cur->_data) > kot(data)){cur = cur->_left;}else{return make_pair(cur, false);}}// 新增节点给红色cur = new Node(data);// 注意,这里需要保存一个新增节点,以便用来返回Node* newnode = cur;cur->_col = RED;// 旋转变色return make_pair(newnode, true);;}

对于set,你可以简单地使用RBTree<K, K, SetKeyOfT>;而对于map,则使用RBTree<K, pair<const K, V>, MapKeyOfT>


📜2. 红黑树的迭代器

🌞迭代器基本设计

// 通过模板来达到const的迭代器的复用
template<class T, class Ref, class Ptr>
struct __TreeIterator
{typedef RBTreeNode<T> Node;typedef __TreeIterator<T, Ref, Ptr> Self;Node* _node;// 构造函数__TreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &(_node->_data);}bool operator!=(const Self& s){return _node != s._node;}
};

🌙begin()与end()

STL明确规定,begin()与end()代表的是一段前闭后开的区间,而对红黑树进行中序遍历后,
可以得到一个有序的序列,因此:begin()可以放在红黑树中最小节点(即最左侧节点)的位
置,end()放在最大节点(最右侧节点)的下一个位置,关键是最大节点的下一个位置在哪块?
能否给成nullptr呢?答案是行不通的,因为对end()位置的迭代器进行–操作,必须要能找最
后一个元素,此处就不行,因此最好的方式是将end()放在头结点的位置

在这里插入图片描述
代码示例(C++):
(注意:此步需要在RBTree类的内部实现),以便map,set的使用

typedef __TreeIterator<T, T&, T*> iterator;
typedef __TreeIterator<T, const T&, const T*> const_iterator;iterator begin()
{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return iterator(cur);
}iterator end()
{return iterator(nullptr);
}const_iterator begin() const
{Node* cur = _root;while (cur && cur->_left){cur = cur->_left;}return const_iterator(cur);
}const_iterator end() const
{return const_iterator(nullptr);
}

⭐operator++()与operator–()

operator++()

  • 右不为空,右子树的最左节点
  • 右为空,沿着到根的路径找孩子是父亲左的那个祖先

operator–()

  • 左不为空,左子树的最右节点
  • 左为空,沿着到根的路径找孩子是父亲右的那个祖先

注意:++和–正好是完全相反的


代码示例(C++):

Self& operator++()
{if (_node->_right){Node* cur = _node->_right;while (cur->_left){cur = cur->_left;}_node = cur;}else{Node* cur = _node;Node* parent = cur->_parent;while (parent && cur == parent->_right){cur = parent;parent = cur->_parent;}_node = parent;}return *this;
}Self& operator--()
{if (_node->_left){Node* cur = _node->_left;while (cur->_right){cur = cur->_right;}_node = cur;}else{Node* cur = _node;Node* parent = cur->_parent;while (parent&& cur == parent->_left){cur = parent;parent = cur->_parent;}_node = parent;}return *this;
}

📚3. Set的模拟实现

🧩Set的基本设计

template<class K>
class set
{
public:// SetKeyOfT:通过T来获取key的一个仿函数类struct SetKeyOfT{const K& operator()(const K& key){return key;}};// typename告诉编译器这是类型,// 因为set不能够进行修改,所以我们用const迭代器来初始化普通迭代器,来达到不能修改的目的typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;iterator begin() const{return _t.begin();}iterator end() const{return _t.end();}// 复用RBTree中的插入pair<iterator, bool> insert(const K& key){return _t.Insert(key);}private:RBTree<K, K, SetKeyOfT> _t;
};

📝4. Map的模拟实现

🧩Map的基本设计

template<class K, class V>
class map
{
public:// MapKeyOfT:通过pair来获取kv.first的一个仿函数类struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};// map是一个key不能修改,value能够修改的结构typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator const_iterator;iterator begin(){return _t.begin();}iterator end(){return _t.end();}// 重载map中的operatorp[]// operatorp[] 当原数据中没有时,插入并初始化,有则修改secondV& operator[](const K& key){// 没有是插入,有则是查找pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}// 复用RBTree中的插入pair<iterator, bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}private:RBTree<K, pair<const K, V>, MapKeyOfT> _t;
};

📖5. 总结

随着我们对红黑树Map与Set的深入探索与模拟实现,这场高效数据存储的旅程也即将画上圆满的句号。回望这段旅程,我们从红黑树的基本概念出发,逐步揭示了其保持平衡、实现高效操作的秘密,并通过亲手编写代码,将理论转化为了实践

同时,我们也要意识到,数据结构的选择并非一成不变。在实际应用中,我们需要根据具体需求、数据规模、性能要求等因素综合考虑,选择最合适的数据结构来解决问题。只有这样,我们才能真正做到高效、稳定地处理数据。

然而,学习之路永无止境。红黑树只是众多高效数据结构中的一种,它们各自有着独特的优势和适用场景。在未来的学习与实践中,我们还需要继续探索其他数据结构,如AVL树、B树、B+树等,以拓宽我们的视野,提升我们的技能

希望各位在未来的学习与工作中,保持对知识的渴望与追求,勇于挑战自我,不断探索未知领域。相信在不久的将来,你们定能在数据处理的广阔舞台上大放异彩

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

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

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

相关文章

js ES6 part1

听了介绍感觉就是把js在oop的使用 作用域 作用域&#xff08;scope&#xff09;规定了变量能够被访问的“范围”&#xff0c;离开了这个“范围”变量便不能被访问&#xff0c; 作用域分为&#xff1a; 局部作用域、 全局作用域 1. 函数作用域&#xff1a; 在函数内部声明的…

爬取天气数据,利用Pyecharts作轮播图

爬取网站链接&#xff1a;https://lishi.tianqi.com/xiamen/202312.html 爬取了厦门市2023年一整年的天气数据&#xff0c;包括最高温&#xff0c;最低温&#xff0c;天气&#xff0c;风力风向等 爬虫代码&#xff1a; import requests import pandas as pd import csv from…

UML建模案例分析-时序图和类图的对应关系

概念 简单地说&#xff0c;类图定义了系统中的对象&#xff0c;时序图定义了对象之间的交互。 例子 一个电子商务系统&#xff0c;会员可通过电子商务系统购买零件。具体功能需求如下&#xff1a; 会员请求结账时&#xff0c;系统验证会员的账户是否处于登录状态&#xff1…

极狐GitLab 17.0 重磅发布,100+ DevSecOps功能更新来啦~【三】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

【基础篇】1.8 C语言基础(二)

2.9 预处理指令和宏定义 在STM32开发中,预处理和宏定义常用于配置硬件参数、启用或禁用特定功能、以及优化代码以适应不同的硬件配置或应用场景。通过合理地使用预处理和宏定义,我们可以编写更加灵活、可配置和高效的代码。 预处理指令如#include、#define等在C语言编程中起…

防火墙图形化界面策略和用户认证(华为)

目录 策略概要认证概要实验拓扑图题目要求一要求二要求三要求四要求五要求六 策略概要 安全策略概要&#xff1a; 安全策略&#xff08;Security Policy&#xff09;在安全领域具有双重含义。宏观上&#xff0c;安全策略指的是一个组织为保证其信息安全而建立的一套安全需求、…

uniapp 微信小程序接入MQTT

MQTT安装 前期准备 由于微信小程序需要wss&#xff0c;所以要有域名SSL证书 新建目录/srv/mosquitto/config&#xff0c;/srv/mosquitto/config/cert 目录/srv/mosquitto/config中新建配置文件mosquitto.conf&#xff0c;文件内容 persistence true persistence_location /m…

深入探索Apache Flink:流处理的艺术与实践

在当今的大数据时代&#xff0c;流处理已成为处理实时数据的关键技术。Apache Flink&#xff0c;作为一个开源的流处理框架&#xff0c;以其高吞吐量、低延迟和精确一次&#xff08;exactly-once&#xff09;的语义处理能力&#xff0c;在众多流处理框架中脱颖而出。本文将深入…

在树莓派设备上导出系统镜像

镜像导出 前提条件&#xff1a; 已获取可以正常使用的设备。已获取鼠标、键盘和电源适配器。已将设备接入可正常使用的网络。 操作步骤&#xff1a; 连接适配器给设备上电&#xff0c;正常启动设备&#xff0c;连接鼠标和键盘。在终端命令窗格执行如下命令&#xff0c;安装…

数据模型-ER图在数据模型设计中的应用

ER图在数据模型设计中的应用 1. ER图概述&#xff1a;起源与发展​ 实体-关系图&#xff08;Entity Relationship Diagram&#xff0c;简称ER图&#xff09;起源于1970年代&#xff0c;由Peter Chen首次提出&#xff0c;作为描述数据和信息间关系的图形化语言。随着数据库技术…

[PM]流程与结构设计

流程图 流程就是为了达到特定目标, 进行的一系列有逻辑性的操作步骤, 由两个及已上的步骤, 完成一个完整的行为过程, 即可称为流程, 流程图就是对这个过程的图形化展示 分类 业务流程图 概念: 描述业务流程的一种图, 通过特定符号和连线表示具体某个业务的处理步骤和过程作…

MyBatis与JDBC相比,有哪些优势

MyBatis与JDBC&#xff08;Java Database Connectivity&#xff09;相比&#xff0c;在多个方面展现出显著的优势。这些优势使得MyBatis在现代软件开发中成为一个非常受欢迎的选择&#xff0c;特别是在处理数据库交互时。以下是MyBatis相比JDBC的主要优势&#xff1a; 1. 简化…

极狐GitLab亮相世界人工智能大会,开启开源大模型赋能软件研发新时代

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

285个地级市-胡焕庸线数据

全国285个地级市-胡焕庸线数据.zip资源-CSDN文库 胡焕庸线&#xff1a;中国人口与生态的分界线 胡焕庸线&#xff0c;一条在中国地理学界具有划时代意义的分界线&#xff0c;由著名地理学家胡焕庸于1935年提出。这条线从黑龙江省的瑷珲&#xff08;现黑河市&#xff09;延伸至…

json-server总结

Json-server 是一个专门用于模拟 RESTful API 的工具&#xff0c;它允许前端开发人员在不依赖后端 API 的情况下进行开发&#xff0c;通过本地搭建一个 JSON 服务来快速生成 REST API 风格的后端服务。 一、主要特点与功能 快速搭建&#xff1a;Json-server 使用 JSON 文件作…

HippoRAG如何从大脑获取线索以改进LLM检索

知识存储和检索正在成为大型语言模型(LLM)应用的重要组成部分。虽然检索增强生成(RAG)在该领域取得了巨大进步&#xff0c;但一些局限性仍然没有克服。 俄亥俄州立大学和斯坦福大学的研究团队推出了HippoRAG&#xff0c;这是一种创新性的检索框架&#xff0c;其设计理念源于人类…

数学建模美赛论文文档

目录 1. 摘要&#xff1a;1.1 阅读并理解题目1.2 背景介绍1.3 问题提出 2. 目录&#xff1a;2.1 引言&#xff08;Introduction&#xff09;2.2 假设与合理性说明&#xff08;Assumptions and Justifications&#xff09;2.3 符号说明&#xff08;Notations&#xff09;2.4 模型…

2.Date类型的请求参数

前端 <el-form-item label"结束日期" prop"endTime"><el-date-pickerv-model"dataForm.endTime"type"date"value-format"yyyy-MM-dd HH:mm:ss"placeholder"选择日期"></el-date-picker></el…

线下线上游戏电竞陪伴APP小程序H5同城线下约玩APP开发,语聊约玩平台搭建游戏陪玩APP源码

开发一款线下陪玩约玩APP的实际意义和在生活中的应用场景 1、满足社交需求:现代社会人们的社交圈往往受到时间、地点和其他限制的影响。线下陪玩约玩APP可以提供一个平台&#xff0c;让用户通过约玩的方式结识新朋友、扩大社交圈 2、解决孤独感:有些人由于工作忙碌、居住环境单…

论文阅读2-《Dynamic Multimodal Fusion》

摘要 &#xff08;DynMM&#xff09;&#xff0c;一种新的方法&#xff0c;自适应融合多模态数据和 d在推理过程中生成依赖于数据的前向路径。为此&#xff0c;我们提出了一种门控功能来提供基于多模态特征和一个的模态级或融合级决策提高计算效率的源感知损失函数。 细节 模…