当前位置: 首页 > news >正文

深入浅出C++ ——红黑树模拟实现STL中的set与map

文章目录

  • 一、红黑树
  • 二、用泛型红黑树模拟实现set
  • 三、用泛型红黑树模拟实现map

一、红黑树

    红黑树作为set和map的底层容器,既要实现插入key又要实现插入pair,所以做了稍许的改动,使其成为一颗泛型结构的红黑树通过不同的实例化参数,实现set和map。如果要生成set,就传(key,key);如果要生成map,就传(key,pair),由第二个参数来控制生成容器的结构。


改动

    在定义模板的红黑树节点时,由template<class K, class V> 改为template<class T>,因为是泛型,所以原本的pair<K, V> _kv;改为T _data;。红黑树的模板template<class K, class V>也改为template<class T> ,在内部代码中,将所有的pair<K, V>都改为Tkv改为data

     在模拟实现set时,定义成员变量为RBTree<K, K> _t; ,在模拟实现map的时候,定义成员变量为RBTree<K, pair<K, V>> _t; 。但是在插入的过程中,比较大小时,不能用data来比较,因为对于map而言,data是pair,要用pair中的first来比较,可以使用仿函数来实现。


set的底层成员

RBTree<K, K, SetKeyOfT> _t;

map的底层成员

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

红黑树的迭代器

     红黑树的begin迭代器是整棵树的最左侧节点,end迭代器是空。

     迭代器++分为两种情况,如果该节点右子树不为空,就找右子树的最左节点。如果该节点的右子树为空,就找祖先里面孩子不是祖先的右的那个。

     迭代器–分为两种情况,如果该节点右子树不为空,就找左子树的最右节点。如果该节点的右子树为空,就找祖先里面孩子不是祖先的左的那个。


泛型红黑树

#pragma once
enum Colour
{RED,BLACK
};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){}
};template<class T, class Ref, class Ptr> //此处的模版参数采用三个可以同时兼顾类型,引用,指针
struct __RBTreeIterator
{typedef RBTreeNode<T> Node;typedef __RBTreeIterator<T, Ref, Ptr> Self;Node* _node;__RBTreeIterator(Node* node):_node(node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}Self& operator++(){if (_node->_right){// 下一个就是右子树的最左节点Node* left = _node->_right;while (left->_left){left = left->_left;}_node = left;}else{// 找祖先里面孩子不是祖先的右的那个Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->_right){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}Self& operator--(){if (_node->_left){// 下一个是左子树的最右节点Node* right = _node->_left;while (right->_right){right = right->_right;}_node = right;}else{// 孩子不是父亲的左的那个祖先Node* parent = _node->_parent;Node* cur = _node;while (parent && cur == parent->_left){cur = cur->_parent;parent = parent->_parent;}_node = parent;}return *this;}
};template<class K, class T, class KeyOfT>
struct RBTree
{typedef RBTreeNode<T> Node;
public:typedef __RBTreeIterator<T, T&, T*> iterator;iterator begin(){Node* left = _root;while (left && left->_left){left = left->_left;}return iterator(left);}iterator end(){return iterator(nullptr);}pair<iterator, bool> Insert(const T& data){KeyOfT kot;if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return make_pair(iterator(_root), true);}Node* parent = nullptr;Node* cur = _root;while (cur){if (kot(cur->_data) < kot(data)){parent = cur;cur = cur->_right;}else if (kot(cur->_data) > kot(data)){parent = cur;cur = cur->_left;}else{return make_pair(iterator(cur), false);}}cur = new Node(data);Node* newnode = cur;cur->_col = RED;if (kot(parent->_data) < kot(data)){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == RED){Node* grandfater = parent->_parent;assert(grandfater);assert(grandfater->_col == BLACK);// 关键看叔叔if (parent == grandfater->_left){Node* uncle = grandfater->_right;// 情况一 : uncle存在且为红,变色+继续往上处理if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfater->_col = RED;// 继续往上处理cur = grandfater;parent = cur->_parent;}// 情况二+三:uncle不存在 + 存在且为黑else{// 情况二:右单旋+变色//     g //   p   u// cif (cur == parent->_left){RotateR(grandfater);parent->_col = BLACK;grandfater->_col = RED;}else{// 情况三:左右单旋+变色//     g //   p   u//     cRotateL(parent);RotateR(grandfater);cur->_col = BLACK;grandfater->_col = RED;}break;}}else // (parent == grandfater->_right){Node* uncle = grandfater->_left;// 情况一if (uncle && uncle->_col == RED){parent->_col = uncle->_col = BLACK;grandfater->_col = RED;// 继续往上处理cur = grandfater;parent = cur->_parent;}else{// 情况二:左单旋+变色//     g //   u   p//         cif (cur == parent->_right){RotateL(grandfater);parent->_col = BLACK;grandfater->_col = RED;}else{// 情况三:右左单旋+变色//     g //   u   p//     cRotateR(parent);RotateL(grandfater);cur->_col = BLACK;grandfater->_col = RED;}break;}}}_root->_col = BLACK;return make_pair(iterator(newnode), true);}void InOrder(){_InOrder(_root);cout << endl;}bool IsBalance(){if (_root == nullptr){return true;}if (_root->_col == RED){cout << "根节点不是黑色" << endl;return false;}// 黑色节点数量基准值int benchmark = 0;return PrevCheck(_root, 0, benchmark);}private:bool PrevCheck(Node* root, int blackNum, int& benchmark){if (root == nullptr){//cout << blackNum << endl;//return;if (benchmark == 0){benchmark = blackNum;return true;}if (blackNum != benchmark){cout << "某条黑色节点的数量不相等" << endl;return false;}else{return true;}}if (root->_col == BLACK){++blackNum;}if (root->_col == RED && root->_parent->_col == RED){cout << "存在连续的红色节点" << endl;return false;}return PrevCheck(root->_left, blackNum, benchmark)&& PrevCheck(root->_right, blackNum, benchmark);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* ppNode = parent->_parent;subR->_left = parent;parent->_parent = subR;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;subL->_right = parent;parent->_parent = subL;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}}private:Node* _root = nullptr;
};

二、用泛型红黑树模拟实现set

#include "TRBTree.hPP"
namespace Jared
{template<class K>class set{//仿函数实现比较struct SetKeyOfT{const K& operator()(const K& key){return key;}};public:typedef typename RBTree<K, K, SetKeyOfT>::iterator iterator;//typename告诉编译器这一段代码是类型,不是静态变量iterator begin(){return _t.begin();}iterator end(){return _t.end();}pair<iterator, bool> insert(const K& key){return _t.Insert(key);}private:RBTree<K, K, SetKeyOfT> _t;};
}

三、用泛型红黑树模拟实现map

#include "TRBTree.hPP"
namespace Jared
{template<class K, class V>class map{//仿函数实现比较struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};public:typedef typename RBTree<K, pair<K, V>, MapKeyOfT>::iterator iterator;//typename告诉编译器这一段代码是类型,不是静态变量iterator begin(){return _t.begin();}iterator end(){return _t.end();}pair<iterator, bool> insert(const pair<K, V>& kv){return _t.Insert(kv);}V& operator[](const K& key){pair<iterator, bool> ret = insert(make_pair(key, V()));return ret.first->second;}private:RBTree<K, pair<K, V>, MapKeyOfT> _t;};
}

相关文章:

深入浅出C++ ——红黑树模拟实现STL中的set与map

文章目录一、红黑树二、用泛型红黑树模拟实现set三、用泛型红黑树模拟实现map一、红黑树 红黑树作为set和map的底层容器&#xff0c;既要实现插入key又要实现插入pair&#xff0c;所以做了稍许的改动&#xff0c;使其成为一颗泛型结构的红黑树&#xff0c;通过不同的实例化参数…...

自动化测试框架设计

大数据时代&#xff0c;多数的web或app产品都会使用第三方或自己开发相应的数据系统&#xff0c;进行用户行为数据或其它信息数据的收集&#xff0c;在这个过程中&#xff0c;埋点是比较重要的一环。 埋点收集的数据一般有以下作用&#xff1a; 驱动决策&#xff1a;ABtest、漏…...

【虚拟仿真】Unity3D中实现鼠标的单击、双击、拖动的不同状态判断

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 这篇文章分享一下虚拟仿真项目中经常碰到鼠标事件控制代码。 …...

【2023】Prometheus-相关知识点(面试点)

目录1.Prometheus1.1.什么是Prometheus1.2.Prometheus的工作流程1.3.Prometheus的组件有哪些1.4.Prometheus有什么特点1.5.Metric的几种类型&#xff1f;分别是什么&#xff1f;1.6.Prometheus的优点和缺点1.7.Prometheus怎么采集数据1.8.Prometheus怎么获取采集对象1.9.Promet…...

英语二-电子邮件邀请短文写作

1. 邮件模板 Dear 邀请人, Hope you have a great day. I am writing this email to invite you to attend 主题. Please kindly find the following information for your reference: Time: 时间 Address: 地点 We hope that nothing will prevent you from coming, as…...

如何快速一次性通过pmp考试?

我们就从三个方向进行了解 1.PMP考试难不难&#xff1f; 2.PMP如何备考&#xff1f; 3.考试过程中需要注意什么&#xff1f; 一&#xff0c;PMP考试难不难&#xff1f; 首先关注的问题是&#xff0c;PMP考试难吗&#xff1f;我想全球55%的通过率和学会这边93.9%的通过率&a…...

1-Linux 保存kernel panic信息到flash

在系统运行过程中&#xff0c;如果内核发生了panic,那么开发人员需要通过内核报错日志来进行定位问题。但是很多时候出现问题的时候没有接调试串口&#xff0c;而报错日志是在内存里面的&#xff0c;重启后就丢失了。所以需要一种方法&#xff0c;可以在系统发生crash时&#x…...

linux基本功系列-top命令实战

文章目录一. top命令介绍二. 语法格式及常用选项三. 参考案例3.1 显示进程信息3.2 显示完整的进程命令3.3 以批处理的形式展示3.4 设置信息更新频次3.5 显示指定进程号的信息3.6 top面板中常用参数3.7 其他用法四. top的相关说明4.1 交互命令介绍4.2 top面板每行信息的含义4.2.…...

6.5 拓展:如何实现 Web API 版本控制,同时兼容无版本控制的原始接口?

第6章 构建 RESTful 服务 6.1 RESTful 简介 6.2 构建 RESTful 应用接口 6.3 使用 Swagger 生成 Web API 文档 6.4 实战&#xff1a;实现 Web API 版本控制 6.5 拓展&#xff1a;如何实现 Web API 版本控制&#xff0c;同时兼容无版本控制的原始接口&#xff1f; 6.5 拓展&#…...

Springboot依赖注入Bean的三种方式,final+构造器注入Bean

文章目录Springboot依赖注入Bean的方式一、Field 注入/属性注入二、set注入三、构造器注入Springboot依赖注入Bean的方式 一、Field 注入/属性注入 Autowired注解的一大使用场景就是Field Injection。 Controller public class UserController {Autowiredprivate UserServic…...

【java】Spring Cloud --Spring Cloud Alibaba 微服务解决方案

文章目录1、Spring Cloud Alibaba 是什么先说说 Spring CloudSpring Cloud Alibaba和Spring Cloud 的区别和联系Spring Cloud Alibaba2、Spring Cloud Alibaba 包含组件阿里开源组件阿里商业化组件集成 Spring Cloud 组件3、Spring Cloud Alibaba 功能服务注册与发现支持多协议…...

CSS 6种选择器(超详细)

CSS6大种选择器(超详细) 一、常用的css基本选择器(4种) 1、标签选择器 结构&#xff1a; 标签名{css属性名&#xff1a;属性值} 作用&#xff1a;通过标签名&#xff0c;找到页面中所有的这类标签&#xff0c;设置样式 注意&#xff1a;1.标签选择器选择的是一类标签&#…...

mysql8.0.32-手动配置安装-具体流程步骤

文章目录1.下载mysql压缩编译版2.修改配置文件3.数据库初始化&#xff0c;安装windows服务&#xff0c;启动服务4.修改root密码5.作者答疑1.下载mysql压缩编译版 作者从官方下载&#xff1a;https://download.csdn.net/download/m0_67316550/87485720 2.修改配置文件 修改my…...

【项目】Vue3+TS 退出登录 menu header搭建

&#x1f4ad;&#x1f4ad; ✨&#xff1a;【项目】Vue3TS 退出登录 menu header搭建   &#x1f49f;&#xff1a;东非不开森的主页   &#x1f49c;: 今天永远比昨天更好&#x1f49c;&#x1f49c;   &#x1f338;: 如有错误或不足之处&#xff0c;希望可以指正&#x…...

LoRaWAN模块在车辆跟踪定位中的应用

目前 GPS已经在资产的管理中得到了越来越多的运用&#xff0c;如车辆跟踪、车队跟踪、资产监控等&#xff1b;人员跟踪&#xff0c;宠物跟踪&#xff0c;等等。在所有追踪装置中&#xff0c;最重要的是它的电池期望和监视距离。鉴于 LoRaWAN的功率消耗很小&#xff0c;而且能在…...

软件测试分类

软件测试分类 从上图我们发现软件测试根据不同的分类条件会有不同的结果. 1. 按照阶段进行划分 1.1 单元测试(Unit Testing) 单元测试是对软件组成单元进行测试。其目的是检验软件基本组成单位的正确性。测试的对象是软件设计的最小单位&#xff1a;模块。 测试阶段&#x…...

外置的媒体查询,对性能又一次的优化提升

通常情况下我们写媒体查询都是写在一个样式文件中&#xff0c;对于浏览器加载的时候&#xff0c;会解析到最后一行样式时才会渲染页面&#xff0c;这样就会造成页面的白屏时间过长。 但是通常情况下大量的媒体查询样式都是无用的&#xff0c;现在浏览器允许我们在引用样式文件…...

【Galois工具开发之路】关于IDEA的gradle工程执行两次premain的bug~

文章目录关于premain方法问题记录解决方式关于premain方法 是Java Agent技术的一种&#xff0c;通过 -javaagent: 的方式&#xff0c;添加外部代理&#xff0c;代理入口方法为 premain 。另一种Java Agent技术则是动态attach到java进程的方式&#xff0c;这种方式则是使用 age…...

云计算 概念与技术

如果我倡导的计算机在未来得到使用&#xff0c;那么有一天&#xff0c;计算也可能像电话一样成为共用设施。计算机应用将成为一全新的、重要的产业的基础。 ——John McCarthy 云计算的概念 定义 Garther公司的定义 一种计算方式&#xff0c;能通过Internet技术将可扩展的和…...

基于追踪标记的WAF设计思路

一 相关背景 目前&#xff0c;市面上的WAF产品通常采用”发现即阻断“的策略&#xff0c;以防护针对业务系统的Web攻击行为。虽然该策略可及时阻断攻击&#xff0c;但形式上过于简单&#xff0c;并不能有效掌握攻击者进一步的攻击意图&#xff0c;也不能有效提高攻击者的成本投…...

TwinCAT3梯形图编程实战:从基础功能到高级应用

1. TwinCAT3梯形图编程入门指南 第一次打开TwinCAT3开发环境时&#xff0c;很多工程师都会被它强大的功能震撼到。作为工业自动化领域的"瑞士军刀"&#xff0c;TwinCAT3的梯形图编程功能尤其适合从传统PLC转型过来的开发者。我刚开始接触时也走过不少弯路&#xff0c…...

Linux进程(下)

上一篇文章介绍了进程的概念和进程的状态&#xff0c;但进程的知识还有很多&#xff0c;本文继续进行讲解。进程的管理指令之前提到过许多对进程进行管理的指令&#xff0c;但没有进行讲解&#xff0c;在这里统一聊聊。核心指令有四个 ps&#xff0c;top&#xff0c;kill&#…...

GPT-SoVITS:革新性少样本语音合成技术深度剖析

GPT-SoVITS&#xff1a;革新性少样本语音合成技术深度剖析 【免费下载链接】GPT-SoVITS 1 min voice data can also be used to train a good TTS model! (few shot voice cloning) 项目地址: https://gitcode.com/GitHub_Trending/gp/GPT-SoVITS 引言&#xff1a;语音合…...

手把手教你用Vivado IBERT给光模块‘体检’:从SFP连接器到误码率报告的完整实战

光模块性能诊断实战&#xff1a;Vivado IBERT从硬件连接到眼图分析的深度解析 当一块全新的ZCU102开发板和一个状态未知的SFP光模块摆在面前时&#xff0c;硬件工程师最关心的问题往往是&#xff1a;这条物理链路到底靠不靠谱&#xff1f;信号质量能否满足设计要求&#xff1f;…...

快速掌握QQ空间历史说说备份:GetQzonehistory完整使用教程

快速掌握QQ空间历史说说备份&#xff1a;GetQzonehistory完整使用教程 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否曾经担心QQ空间里的珍贵记忆会随着时间流逝而消失&#xff…...

MATLAB连续潮流程序:IEEE节点标准PV曲线绘制工具,支持14节点与33节点系统,具备分...

matlab连续潮流程序绘制PV曲线 静态电压稳定 该程序为连续潮流IEEE14节点和33节点的程序 运行出来有分岔点和鼻点 可移植性强&#xff0c;注释详细 这段程序主要是用来计算电力系统中的潮流分布&#xff0c;并绘制PV曲线。下面我将对程序进行详细的分析。首先&#xff0c;程序开…...

新手福音:通过快马平台零代码基础玩转picoclaw机器人板

作为一个刚接触嵌入式开发的新手&#xff0c;拿到picoclaw控制器时既兴奋又忐忑。这块小小的板子能控制电机、读取传感器&#xff0c;但如何让它动起来却让我一头雾水。好在发现了InsCode(快马)平台&#xff0c;不需要从零开始啃文档&#xff0c;就能快速生成可运行的示例代码。…...

2026最权威的十大AI写作工具实测分析

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 人工智能技术于毕业论文写作进程当中的运用愈发广泛&#xff0c;其关键价值在于提高研究效率…...

ai赋能安装:让快马智能推荐openclaw本地部署的最优配置方案

最近在折腾OpenClaw的本地安装&#xff0c;发现这个爬虫框架虽然强大&#xff0c;但配置起来真是让人头大——不同的硬件环境和应用场景需要完全不同的参数组合。好在发现了InsCode(快马)平台的AI辅助开发功能&#xff0c;用它做了个智能配置工具&#xff0c;分享下实现思路和实…...

opencv透视变换实战:从算法原理到图像矫正的完整实现

1. 透视变换的数学原理与生活场景 第一次接触透视变换时&#xff0c;我盯着那些数学公式看了整整一个下午。直到有天在咖啡厅看到服务员端盘子&#xff0c;突然就明白了——这就像把倾斜的餐盘拍平的过程。想象你从侧面45度角拍了一张餐盘照片&#xff0c;透视变换就是把这个斜…...