当前位置: 首页 > 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.lryc.cn/news/600616.html

相关文章:

  • element-plus安装以及使用
  • 机器人仿真(2)Ubuntu24.04下RTX5090配置IsaacSim与IsaacLab
  • Java实现大根堆与小根堆详解
  • 【数据结构】栈和队列的实现
  • 基于DataX的数据同步实战
  • 详解力扣高频SQL50题之1141. 查询近30天活跃用户数【简单】
  • STM32-定时器的基本定时/计数功能实现配置教程(寄存器版)
  • 手动开发一个串口调试工具(二):Qt 串口类基本认识与使用
  • ClickHouse高性能实时分析数据库-消费实时数据流(消费kafka)
  • 【Linux系统】理解硬件 | 引入文件系统
  • Kotlin线程同步
  • 高并发微服务限流算法方案对比与实践指南
  • 告别Vite脚手架局限!MixOne Beta测试招募:你的需求,我们来实现
  • 基于 ThinkPHP 开发的垂直化网址导航
  • 深入解析Hadoop如何实现数据可靠性:三副本策略、校验和验证与Pipeline复制
  • 使用Spring Boot创建Web项目
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频语义理解与智能检索进阶(365)
  • 【工程化】浅谈前端构建工具
  • nginx一个域名下部署多套前端项目
  • 机器学习特征工程详解:特征选择与降维(PCA)
  • NLua和C#交互
  • Flask input 和datalist结合
  • VTK交互——ImageClip
  • xLua和C#交互
  • 高性能网络DPDK、RDMA、XDP初探
  • 电子电气架构 --- 高阶智能驾驶对E/E架构的新要求
  • 工具 | 解决 VSCode 中的 Delete CR 问题
  • uniapp+vue3——通知栏标题纵向滚动切换
  • 全球化2.0 | 云轴科技ZStack亮相阿里云印尼国有企业CXO专家活动
  • 以太坊下一阶段的关键——隐私