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

进阶数据结构:用红黑树实现封装map和set

嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的
passion。准备好和我一起冲进代码的奇幻宇宙了吗?Let’s go!

请添加图片描述

我的博客:yuanManGan

我的专栏:C++入门小馆 C言雅韵集 数据结构漫游记 闲言碎语小记坊
进阶数据结构 走进Linux的世界 题山采玉 领略算法真谛

在这里插入图片描述


用红黑树实现封装map和set


实现步骤:

  1. 实现红黑树
  2. 封装 mapset 框架解决KeyOfT
  3. iterator
  4. const_iterator
  5. key不支持修改的问题
  6. operator[ ]

1.实现红黑树

上集我们已经实现了一个普通的红黑树 进阶数据结构:红黑树,


2.封装 map 和 set 框架解决KeyOfT


查看stl源码借鉴了解

发现实现 setmap 都包含了一个 tree 头文件,我们那篇博客实现的 key-value 的红黑树,那我们是不是要实现两个红黑树一个是 key 的一个 key-value 的呢?
stl中实现set和map所包含的头文件


不急我们看看源码:

template<typename _Key, typename _Val, typename _KeyOfValue,typename _Compare, typename _Alloc = allocator<_Val> >class _Rb_tree{}

我们凑凑这模板,这怎么又有key又有value那它怎么实现的set , set 不是不要value吗?


我来解释一下吧:

  • 可能写这个代码的程序员写的不太规范,这个地方的Val代表的不是我们之前写代码的value
  • 而是比如我们set传入的keymap传入的key_value,代表的是这一类,而不是单纯的value
  • 我们就这样形成了模板,本质上编译器还是写了两份代码,但增加了复用,减少了我们自己写。

那又有人问了,那我们不是只要一个模板参数就够了吗,为什么前面还得加个key呢?

  • 我们实现 find 等功能的时候需要使用到 key,所以不能偷懒

更改我们的红黑树

我们写就写的规范一点,我们将 V 替换为 T

//原本
////////////////////////////////////////////////////////////////
template <class K,class V>
struct RBTreeNode
{pair<K, V> _kv;RBTreeNode<K, V>* _parent;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;Colour _col;RBTreeNode(const pair<K, V>& kv): _kv(kv), _parent(nullptr), _left(nullptr), _right(nullptr)  // 按声明顺序放在_col之前, _col(RED){}
};
template <class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public://...
private:Node* _root = nullptr;
};
////////////////////////////////////////////////////////////////
//修改后
template <class T>
struct RBTreeNode
{T _data;RBTreeNode<T>* _parent;RBTreeNode<V>* _left;RBTreeNode<V>* _right;Colour _col;RBTreeNode(T& data): _data(data), _parent(nullptr), _left(nullptr), _right(nullptr)  // 按声明顺序放在_col之前, _col(RED){}
};
template <class K, class T>
class RBTree
{typedef RBTreeNode<K, T> Node;
public://...
private:Node* _root = nullptr;
};

我们在修改 Insert 这个函数的时候就遇到的问题,我们怎么比较插入节点与原节点的大小呢?

  • 我们可以引入一个模板参数 KeyOfT 分别在 setmap头文件里面重载 ( ) 实现比较逻辑,如果是set就直接返回 keymap就返回kv中的 first

//set.h
template<class K>
class set
{struct SetKeyOfT{const K& operator()(const K& key){return key;}};
public://...
private:RBTree<K, K, SetKeyOfT> _t;	
};
//map.h
template<class K, class V>
class map
{struct MapKeyOfT{const K& operator()(const pair<K, V>& kv){return kv.first;}};
public://...
private:RBTree<K, pair<K, V>, MapKeyOfT> _t;	
};
  • insert
KeyOfT kot;
bool Insert(const T& data)
{//插入//空树if (_root == nullptr){_root = new Node(data);_root->_col = BLACK;return true;}Node* cur = _root;Node* parent = nullptr;while (cur){if (kot(data) > kot(cur->_data)){parent = cur;cur = cur->_right;}else if (kot(data) < kot(cur->_data)){parent = cur;cur = cur->_left;}else {return false;}}cur = new Node(data);cur->_col = RED;if (kot(data) > kot(parent->_data)){//是p的右子树parent->_right = cur;}else{//是p的左子树parent->_left = cur;}cur->_parent = parent;//变色while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (grandfather->_left == parent){Node* uncle = grandfather->_right;//u存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续往上处理cur = grandfather;parent = cur->_parent;}else{//u存在但为黑if (cur == parent->_left){//c在左//     g           p  //   p   u --->  c   g// c                   uRotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else{//c在右//     g    RotateL(p)        g    RotateR(g)    c//  p     u ----------->   c     u -------->  p     g//     c                 p                             u      RotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else{Node* uncle = grandfather->_left;//u存在且为红if (uncle && uncle->_col == RED){//变色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续往上处理cur = grandfather;parent = cur->_parent;}else{//u存在但为黑if (cur == parent->_right){//c在右//     g           p  //   u   p --->  g   c//         c   uRotateL(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else{//c在z左//     g    RotateR(p)      g    RotateL(g)    c//  u     p -----------> u     c -------->  g     p//     c                        p        u      RotateR(parent);RotateL
http://www.dtcms.com/a/299733.html

相关文章:

  • Sql server查询汇总补缺月份
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 热词评论查询功能实现
  • Android开发中内存泄漏问题治理方案
  • 四通OKI5560SC针式打印机如何复位清零和恢复出厂设置??
  • 昇思学习营-昇思+香橙派+deepseek介绍课程内容及心得
  • Chukonu 阅读笔记
  • Rerank 模型的其中两种路径:BERT 相似度与 CoT 推理
  • 如何应对心事干扰学习工作?
  • 高可用集群KEEPALIVED的详细部署
  • 【CTF-Web】dirsearch寻找download.php进行?path=flag.txt任意文件下载
  • 深入解析命名管道:原理、实现与进程间通信应用
  • 机器学习对中特估股票关键特征选取的应用与研究
  • 【橘子分布式】gRPC(番外篇-监听流)
  • Thinkph6中常用的验证方式实例
  • 【时时三省】(C语言基础)用指向函数的指针作函数参数
  • 网络:应用层
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-30,(知识点:传输线特性阻抗,影响因素)
  • 【web应用】基于Vue3和Spring Boot的课程管理前后端数据交互过程
  • 1、虚拟机安装
  • InfluxDB Flux 查询协议实战应用(二)
  • Linux726 raid0,raid1,raid5;raid 创建、保存、停止、删除
  • Python 程序设计讲义(22):循环结构——for 循环
  • 使用FRP搭建内网穿透工具,自己公网服务器独享内外网端口转发
  • C++ APM异步编程模式剖析
  • 2025微前端架构研究与实践方案
  • 【6G新技术探索】AG-UI(Agent User Interaction Protocol) 协议介绍
  • Flutter开发实战之动画与交互设计
  • Java 注解(Annotation)详解:从基础到实战,彻底掌握元数据驱动开发
  • 详细介绍MySQL的索引类型
  • mybatis-plus从入门到入土(三):持久层接口之IService