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

news2024/9/30 13:22:02

📝个人主页🌹: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[] 当原数据中没有时,插入并初始化,有则修改second
	V& 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.coloradmin.cn/o/1913345.html

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

相关文章

【RHCE】转发服务器实验

1.在本地主机上操作 2.在客户端操作设置主机的IP地址为dns 3.测试,客户机是否能ping通

PHP禁止IP访问和IP段访问(代码实例)

PHP禁止IP和IP段访问 实现IP限制是Web开发中常见的需求之一&#xff0c;它可以用于限制特定IP地址的访问权限。在PHP中&#xff0c;我们可以通过一些方法来实现IP限制。 <?//禁止某个IP$banned_ip array ("127.0.0.1",//"119.6.20.66","192.168.…

使用CANoe创建仿真项目并执行

使用CANoe创建开关控制灯亮灯灭的仿真环境 一、创建仿真工程 1.在某盘符下创建一个文件夹&#xff0c;命名为testpanel(自定义&#xff0c;与项目相关)&#xff0c;在文件夹testpanel下面分别创建CANdb、Panels和Nodes文件目录 2.打开CANoe&#xff0c;单击File→New&#xff…

分享中国-吉林省和9个地级市州人文地图

分享中国-吉林省和9个地级市州人文地图 1、吉林省 吉林省&#xff0c;位于中国东北地区中部&#xff0c;地处东北亚地理中心位置&#xff0c;因吉林市而得名&#xff0c;清康熙时在松花江畔建吉林乌拉城&#xff0c;满语意为“沿江的地方”。 吉林省以中部大黑山为界&#x…

How do I format markdown chatgpt response in tkinter frame python?

题意&#xff1a;怎样在Tkinter框架中使用Python来格式化Markdown格式的ChatGPT响应&#xff1f; 问题背景&#xff1a; Chatgpt sometimes responds in markdown language. Sometimes the respond contains ** ** which means the text in between should be bold and ### te…

[AI 大模型] Meta LLaMA-2

文章目录 [AI 大模型] Meta LLaMA-2简介模型架构发展新技术和优势示例 [AI 大模型] Meta LLaMA-2 简介 Meta LLaMA-2 是 Meta 推出的第二代开源大型语言模型&#xff08;LLM&#xff09;&#xff0c;旨在为研究和商业应用提供强大的自然语言处理能力。 LLaMA-2 系列模型包括从…

华为OD机试 - 二叉树的广度优先遍历 - 二叉树(Java 2024 D卷 200分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

算丰 2300x-SOC TPU 处理器体验,运行 langchain + chatglm3 知识库,评测对话效果海口有几个机场 | Chatopera

处理器 算丰 2300x-SOC&#xff0c;国产 AI 芯片 处理器效果不错&#xff0c;使用 models/glm3_model/chatglm3-6b_int4_1dev_2k.bmodel 达到 8.9 Token/s 知识库项目 ChatDoc-TPU 验证过程 但是知识库运行的效果差强人意&#xff0c;有待提升。过程如下&#xff1a; 上…

Kithara和OpenCV (一)

Kithara使用 OpenCV 目录 Kithara使用 OpenCV简介需求和支持的环境构建 OpenCV 库使用 CMake 进行配置以与 Kithara 一起工作 使用 OpenCV 库设置项目运行 OpenCV 代码图像采集和 OpenCV自动并行化限制和局限性1.系统建议2.实时限制3.不支持的功能和缺失的功能4.显示 OpenCV 对…

Centos7 被停用!如何利用 Ora2Pg 将 Oracle 迁移至 IvorySQL?

在过去的社区讨论中&#xff0c;想要使用或正在使用IvorySQL的社区用户&#xff0c;经常问到Oracle 如何迁移到 IvorySQL 中&#xff0c;而且近期随着 Centos7 官方已经停止维护&#xff0c;这一变动促使了很多将 Oracle 部署在 Centos7 上的 Oracle 用户&#xff0c;开始准备 …

深度学习之梯度消失

在深度学习中&#xff0c;梯度消失是指在反向传播过程中&#xff0c;随着网络层数增加或者在使用特定类型的激活函数&#xff08;如sigmoid函数&#xff09;时&#xff0c;梯度逐渐变小并最终趋近于零的现象。这种现象导致在更新参数时&#xff0c;底层网络的权重几乎不会得到有…

增强现实(AR)与虚拟现实(VR)的区别?

随着科技的飞速发展&#xff0c;增强现实&#xff08;AR&#xff09;与虚拟现实&#xff08;VR&#xff09;技术在各个领域展现出巨大的潜力和应用前景。这两种技术虽然在体验和实现方式上有所不同&#xff0c;但都为用户提供了全新的感知体验。本文将详细解析AR和VR的概念、区…

mysql查询的一些问题

解决方案一&#xff1a;给字段起别名&#xff0c;让别名与实体类属性一致 解决方案二&#xff1a;通过Results和Result注解手动映射 推荐使用方案三&#xff1a;开启驼峰命名在application.properties文件中添加mybatis.configuration.map-underscore-to-camel-casetrue

基于Java中的SSM框架实现疫情冷链追溯系统项目【项目源码+论文说明】

基于Java中的SSM框架实现疫情冷链追溯系统演示 摘要 近几年随着城镇化发展和居民消费水平的不断提升&#xff0c;人们对健康生活方式的追求意识逐渐加强&#xff0c;生鲜食品逐渐受到大众青睐&#xff0c;诸如盒马鲜生、7-fresh等品牌生鲜超市&#xff0c;一时间如雨后春笋般迅…

280个地级市金融集聚水平数据(2006-2022年)

2006年-2022年280个地级市金融集聚水平数据整理资源-CSDN文库 金融集聚水平&#xff1a;衡量地级市金融发展的新维度 金融集聚水平是衡量一个地区金融发展程度的重要指标&#xff0c;它反映了金融机构、金融资源、金融服务在特定时间和空间的集中程度。这一指标的评估可以从多…

【常见开源库的二次开发】一文学懂CJSON

简介&#xff1a; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式。它基于JavaScript的一个子集&#xff0c;但是JSON是独立于语言的&#xff0c;这意味着尽管JSON是由JavaScript语法衍生出来的&#xff0c;它可以被任何编程语言读取和生成…

UML 2.5图的分类

新书速览|《UML 2.5基础、建模与设计实践》新书速览|《UML 2.5基础、建模与设计实践 UML 2.5在UML 2.4.1的基础上进行了结构性的调整&#xff0c;简化和重新组织了 UML规范文档。UML规范被重新编写&#xff0c;使其“更易于阅读”&#xff0c;并且“尽可能减少前向引用”。 U…

硬盘分区读不出来的应对策略与数据恢复实战

在日常的计算机使用过程中&#xff0c;硬盘分区读不出来的问题时常困扰着用户。这一故障不仅可能导致重要数据的突然失联&#xff0c;还可能对系统的稳定运行造成威胁。硬盘分区读不出来&#xff0c;往往表现为在文件资源管理器中无法访问特定分区&#xff0c;系统提示错误或分…

java中方法的使用

方法的使用 方法的概念什么是方法方法定义方法的调用过程实参和形参的关系 方法重载为什么需要方法重载方法重载的概念方法签名 递归递归的概念递归过程分析递归练习 方法的概念 什么是方法 方法就是一个代码片段&#xff0c;类似于C语言的函数。 方法存在的意义&#xff1a;…

MySQL 面试相关问题

1. MySQL 基础问题1.1 为什么用MySQL&#xff1f;1.2 表属性类型 varchar 和 char 的区别&#xff1f;1.2 什么时候用 varchar 和 char&#xff1f;1.3 Datetime 和 Timestamp 的区别&#xff1f;1.4 一个SQL语句的执行过程&#xff0c;表述下&#xff1f; 2. MySQL 存储引擎相…