波奇学C++:用红黑树模拟实现map和set

news2024/11/28 9:39:54

用同一个树的类模板封装map(key/value)和set(key)

红黑树的Node

template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _data;
	Colour _col;
	RBTreeNode(const T& data)
		:_left(nullptr)
		,_right(nullptr)
		,_parent(nullptr)
		,_data(data)
		,_col(BLACK)
	{}
};

用只有一个data变量来代替map的pair<key,value> 和set的key

template<class key,class T,class KeyOfT>
struct RBTree

看红黑树的模板的我们依然保留key模板,对于Set来说key和T都是value的,对于map来说key 是 key,T是pair<key,value>。

RBTree<K, pair<K, V>,MapKeyOfT> _t;
RBTree<K, K,SetKeyOfT> _t;

由此相当于适配器模式,对于set来说第二个模板参数不是必要的。

由此我们可以思考,我们对两个对象的封装可以先统一起来某种形式,比如都提供两个模板参数。

红黑树的insert返回值由原来的bool变成了pair<iterator,bool>

pair<iterator,bool> Insert(const T& data)
//......
return make_pair(iterator(newnode), true);
//

注意实际上map和set的迭代器属性不一样,但我们返回权限大的普通迭代器,后面再分别进行const限制来适配

typedef __TreeIterator<T,T*,T&> iterator;

写红黑树的迭代器

template<class T, class Ptr, class Ref>
struct __TreeIterator
{
	typedef RBTreeNode Node;
	typedef __TreeIterator< T, Ptr, Ref> Self;
	// Iterator只可能是普通迭代器
	typedef __TreeIterator< T, T*, T&> Iterator;
	Node* _node;
	__TreeIterator(const Iterator& It)
		:_node(It._node)
	{}
	__TreeIterator(Node* node)
		:_node(node)
	{}
	 Ref operator*()
	{
		return _node->_data;
	}
	 Ptr operator->()
	 {
		 return &_node->_data;
	 }
	 Self& operator++()
	 {
		 //右边不为空
		 if (_node->right)
		 {
			 Node* leftmin = _node->_right;
			 while (leftmin->_left)
			 {
				 leftmin = leftmin->_left;
			 }
			 _node = leftmin;
			 return *this;
		 }
		 else
		 {// 右树为空
			 Node* parent = _node->_parent;
			 while (parent&&_node == parent->right)
			 {
				 _node = parent;
				 parent = _node->_parent;
			 }
			 _node = parent;
			 return *this;
		 }
	 }
	 bool operator!=(const Iterator it)const
	 {
		 return _node != it._node;
	 }
	 bool operator==(const Iterator)const
	 {
		 return _node == it._node;
	 }
	 Self& operator--()
	 {
		 //左不为空
		 if (_node->_left)
		 {
			 Node* rightmax = _node->_left;
			 while (rightmax->_right)
			 {
				 rightmax = rightmax->_right;
			 }
			 _node = rightmax;
			 return *this;
		 }
		 else
		 {
			 Node* parent = _node->_parent;
			 while (parent && parent->_right == _node)
			 {
				 _node = parent;
				 parent = _node->_parent;
			 }
			 _node = parent;
			 return *this;
		 }
	 }

};

比较重要的点是拷贝构造函数

__TreeIterator(const Iterator& It)
		:_node(It._node)
	{}

对于普通迭代器,是拷贝构造,同时它也可以接收普通迭代器来构造const 修饰的迭代器。

operate()++的分析

当右树存在时,再右子树的最大值,当右树不存在,找到parent节点向上处理,当cur是parentd1左节点时,parent就是下一个节点。

红黑树的begin(),end()方法 

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

这里用了没有直接返回Node*指针而是返回迭代器对象,调用拷贝构造函数。

map和set的迭代器有不同的需求,对于set而言,iterator就是const_iterator。

typedef typename RBTree<K, K, SetKeyOfT>::const_iterator iterator;
typedef typename RBTree<K, K, SetKeyOfT>::const_iterator const_iterator;

set的begin() 

iterator begin()
{
	return _t.begin();
}
	

当begin()调用时 _t.begin()返回的是iterator这是就是可以通过__TreeIterator的拷贝构造实现转换成Iterator,(其实可以直接调用const的begin()修饰的函数)

insert封装

pair<iterator, bool> insert(const K& key)
		{
			pair<typename RBTree<K, K, SetKeyOfT>::iterator, bool>ret = _t.Insert(key);
			return pair<iterator, bool>(ret.first, ret.second);
		}

注意此时的问题,insert规定返回值必须是pair<iterator, bool>,RBTree返回的值实际是iterator,myset返回的iterator实际是const_iterator。不能直接返回会导致权限的缩小,所以要再构造。

而map的迭代器要确保pair<key,value>的key不会改变。方法是给模板参数上const

typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::iterator iterator;
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::const_iterator const_iterator;

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

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

相关文章

python工具-内存采集展示

1. 查看某个进程的内存占用 1. 查看某个进程的内存占用 1.1. 采集1.2. 分析 1.1. 采集 下边内存保存为 cat-memory.sh 脚本文件&#xff0c;赋予可执行权限执行 ./cat-memory.sh pid 会生成 pid.txt #!/bin/bashprocess$1 out$1.txt pid$1echo 时间 内存(KB) >> $ou…

复旦大学EMBA:揭秘科创企业,领略未来战略!

智能制造&#xff0c;国之重器。作为制造强国建设的主攻方向&#xff0c;智能制造的发展水平关系到我国未来制造业在全球的地位与影响力。发展智能制造&#xff0c;是加快建设现代化产业体系的重要手段&#xff0c;提升供给体系适配性的有力抓手&#xff0c;也是建设数字中国的…

E. Monsters

Problem - 1810E - Codeforces 思路&#xff1a;我们总结一下题意&#xff0c;能够得到这个题其实就是让我们从某个0开始搜索&#xff0c;然后看看是否可以遍历所有得节点&#xff0c;那么如果采用暴力得话那就是n^2logn&#xff0c;因为我们遍历一次使用优先队列得话是nlogn的…

Stm32_标准库_8_ADC_光敏传感器_测量具体光照强度

ADC简介 测量方式 采用二分法比较数据 IO通道 ADC基本结构及配置路线 获取数字变量需要用到用到光敏电阻的AO口&#xff0c;AO端口接在PA0引脚即可 测得的模拟数据与实际光照强度之间的关系为 光照强度 100 - 模拟量 / 40;代码&#xff1a; 完整朴素代码&#xff1a; #in…

Mysql存储-EAV模式

Mysql存储-EAV模式 最近又又又搞一点新东西&#xff0c;要整合不同业务进行存储和查询&#xff0c;一波学习过后总结了一下可扩展性MAX的eav模式存储。 在eav这里的数据结构设计尤为关键&#xff0c;需要充分考虑你需要使用的字段、使用场景&#xff0c;当数据结构设计完成后便…

skywalking功能介绍

服务 服务信息 请求接口后查看skywalking&#xff0c;可以看到有一个请求&#xff0c;响应时间为1852ms&#xff0c;性能指数Apdex为0.5。 详细表盘 点进应用可以看到表盘 可以看到显示有一个slow endpoints&#xff0c;就是我请求的这个接口。 JVM信息 也可以看到JVM信息。…

点餐小程序实战教程06-首页开发

用户注册功能开发好了之后&#xff0c;我们就要开发小程序&#xff0c;首先我们是规划小程序的功能模块&#xff0c;我们一共是四个模块&#xff0c;分别是首页、订单、消息和我的。 首页我们主要是点餐的功能&#xff0c;可以选择菜品&#xff0c;加入到购物车&#xff0c;然…

deckGL自定义图层学习笔记

1.自定义图层 当使用DeckGL提供的图层还无法满足需求时&#xff08;https://deck.gl/docs/api-reference/layers&#xff09;&#xff0c;可能就需要自定义图层了。在DeckGL中有常见的三种自定义图层的方式 创建复合层&#xff08;composite layers.&#xff09;——复合层是一…

ffmpeg从一个视频中提取音频

ffmpeg -i ~/video/video.mp4 -vn -acodec copy ~/video/audioFile.m4a 从video.mp4中提取音频到文件audioFile.m4a中 查看提取的音频文件 ffprobe ~/video/audioFile.m4a

OneDrive下的OneNote扩容方法,及查看OneDrive容量的方法(详细图文教程)

目录 一、内存不足的问题二、土豪续费扩容法三、X宝扩容法3.1 购买链接3.2 登录接口3.3 详细图文操作过程3.3.1 获取链接&#xff1a;3.3.2 用订单号和获取链接扩容&#xff1a; 3.4 扩容后的容量 四、查看自己OneDrive的容量五、总结 一、内存不足的问题 一直都在用OneNote记…

STM32H723 CubeMX 三路FDCAN 代码

时钟频率 FDCAN1 设置250kbit/s FDCAN2 设置500kbit/s FDCAN3 设置500kbit/s fdcan.c /* USER CODE BEGIN Header */ /********************************************************************************* file fdcan.c* brief This file provides code fo…

【刷题篇】回溯算法(深度优先搜索(二))

文章目录 岛屿数量电话号码的字母组合组合总和活字印刷 岛屿数量 给你一个由 ‘1’&#xff08;陆地&#xff09;和 ‘0’&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直…

CentOS7.9中使用packstack安装train版本

这里写目录标题 材料准备为什么选择packstack安装静态ip系统配置使用阿里云yum源安装packstack部署openstack 安装成功和后续使用all in one模式下虚拟机外网和浮动ip原理讲解nat网桥的创建方法 材料准备 ecs云服务器8核心16g内存一台&#xff0c;系统盘100GB&#xff0c;系统…

2.2 数据通信的基础知识

前言&#xff1a; 2.2.1 数据通信的基础知识 **笔记**&#xff1a;2.2.1 数据通信系统的模型 --- **1. 数据通信系统组成**&#xff1a; - 三大部分&#xff1a; 1. 源系统 (发送端) 2. 传输系统 (传输网络) 3. 目的系统 (接收端) --- **2. 源系统**&#xff1a; -…

vue-4

一、文章内容概括 1.组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; ​ scoped解决样式冲突/data是一个函数 2.组件通信 组件通信语法父传子子传父非父子通信&#xff08;扩展&#xff09; 3.进阶语法 v-model原理v-model应用于组件sync修饰符ref和$refs$nex…

SAP SMARTFORMS 文本框显示默认浏览器

问题描述&#xff1a;新上的SAP系统SMARTFORMS文本框显示浏览器&#xff0c;导致无法拉取系统变量 解决方法&#xff1a; 类CL_COS_UTILITIES做隐式增强 IF sy-tcode SMARTFORMS.rv_is_s4h .ENDIF. 然后执行程序&#xff1a;RSCPSETEDITOR 把这俩√去掉后激活即可

MISRA C 2012 阅读笔记

背景 C语言诞生至今已有50年&#xff0c;因其语言简洁&#xff0c;语法丰富&#xff0c;可移植性高&#xff0c;和执行效率高等优点&#xff0c;至今仍保持着强大的生命力&#xff0c;在各个行业发挥着作用。 然而C语言的一些优点有时候也是一把双刃剑&#xff0c;在使用者使用…

Acwing.886 求组合数Ⅱ

题目 给定n组询问&#xff0c;每组询问给定两个整数a&#xff0c; b&#xff0c;请你输出 的值。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含—组a和b。 输出格式 共n行&#xff0c;每行输出—个询问的解。 数据范围 1<n≤10000, 1 <b<a≤105…

Acwing.889 满足条件的01序列

题目 给定n个0和n个1&#xff0c;它们将按照某种顺序排成长度为2n的序列&#xff0c;求它们能排列成的所有序列中&#xff0c;能够满足任意前缀序列中0的个数都不少于1的个数的序列有多少个。 输出的答案对109&#xff0b;7取模。 输入格式 共一行&#xff0c;包含整数n。 …

【python】python虚拟环境--20231008

https://blog.csdn.net/m0_69023493/article/details/129158656 安装好python和pip 略 新建python虚拟空间 安装virtualenv pip install virtualenv -i https://pypi.tuna.tsinghua.edu.cn/simple安装virtualenvwrapper-win&#xff08;可选&#xff09; pip install vir…