欢迎来到我的频道 【点击跳转专栏】
码云链接 【点此转跳】
文章目录
- [0. 前言](#0. 前言)
- [1. set&&map的基本结构](#1. set&&map的基本结构)
- [2. 迭代器的模拟实现](#2. 迭代器的模拟实现)
- [3. Insert的实现](#3. Insert的实现)
- [4. map的【】实现](#4. map的【】实现)
- 5.完整代码
- [5.1 <红黑.h>](#5.1 <红黑.h>)
- [5.2 <set.h>](#5.2 <set.h>)
- [5.3 <map.h>](#5.3 <map.h>)
- [5.4 测试样例代码](#5.4 测试样例代码)
0. 前言
学习本章节 必须掌握 红黑树的实现和 set&&map 的基本使用
1. set&&map的基本结构
我们利用红黑树对map和set进行封装 首先我们要先根据地层确定他们的结构 set是key 、key的形式,而map是key、value的形式。
第一个难点就是在红黑树结构中表示出他们不同的形态 第二个点就是为什么要使用<K,K>或者<K,pair<K,V>的形式 第二个问题比较好回答 这里的目的是为了 第一个参数作为索引参数(比如插入,查找操作用的就是第一个参数K),而第二个参数就是类型参数(说人话就是值)。
第一个问题我们可以通过仿函数的形式 通过仿函数返回我们所需要的的值
cpp
// 定义节点颜色:红或黑
enum Colour
{
RED,
BLACK
};
// 红黑树节点模板定义
template<class T>
struct RBTreeNode
{
T _data; // 节点存储的数据(如 key 或 pair<key, value>)
RBTreeNode<T>* _left; // 左子节点指针
RBTreeNode<T>* _right; // 右子节点指针
RBTreeNode<T>* _parent; // 父节点指针(用于旋转、插入调整和迭代器回溯)
Colour _col; // 节点颜色(RED / BLACK)
// 构造函数:初始化数据,指针置空,颜色默认为 RED(新插入节点通常为红)
RBTreeNode(const T& data)
: _data(data)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
// 注意:_col 未在此初始化,但在 Insert 中会显式设为 RED
{}
};
// 红黑树主类模板
// K: 键类型(用于查找)
// T: 节点存储类型(如 pair<K, V>)
// KeyOfT: 仿函数,用于从 T 中提取 K(如 map 用 first,set 用自身)
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
};
cpp
// 模拟 STL 中的 std::set:基于红黑树实现的有序、唯一元素集合
template<class K>
class set
{
public:
// 仿函数:用于从 set 的节点数据中提取 key
// 因为 set 中每个节点只存 key(即 T == K),所以直接返回自身
struct SetKeyOfT
{
// 接收一个 const K&(即节点存储的数据),返回其 key(就是它自己)
const K& operator()(const K& key)
{
return key;
}
};
private:
// 红黑树成员:
// - 键类型:K
// - 节点存储类型:const K(强调 set 中元素不可被修改)
// - Key 提取器:SetKeyOfT(返回自身)
RBTree<K, const K, SetKeyOfT> _t;
};
cpp
// 模拟 STL 中的 std::map:基于红黑树实现的有序键值对容器
// 键(K)唯一,值(V)可修改;整体按键排序
template<class K, class V>
class map
{
public:
// 仿函数:用于从 map 节点数据(pair<K, V>)中提取 key
struct MapKeyOfT
{
// 接收一个 pair<K, V> 类型的节点数据,返回其 key(即 .first)
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
private:
// 红黑树成员变量:
// - 键类型:K
// - 节点存储类型:pair<const K, V>
// → 键为 const,防止用户通过迭代器修改 key(破坏树结构)
// - Key 提取器:MapKeyOfT(从 pair 中取 .first 作为比较依据)
RBTree<K, pair<const K, V>, MapKeyOfT> _t;
}
⚠️:这里要特别注意
set里面 第二个K和map中pair<K,V>中K必须是const的形式
为了更好的对比 红黑树和map&&set二者的映射关系 小编特地把里面最核心的东西提取出来方便大家进行对比
cpp
template<class K, class V>
class map
{
RBTree<K, const K, SetKeyOfT> _t;
};
template<class K>
class set
{
RBTree<K, const K, SetKeyOfT> _t;
};
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
};
template<class T>
struct RBTreeNode
{
T _data; // 节点存储的数据(如 key 或 pair<key, value>)
RBTreeNode<T>* _left; // 左子节点指针
RBTreeNode<T>* _right; // 右子节点指针
RBTreeNode<T>* _parent; // 父节点指针(用于旋转、插入调整和迭代器回溯)
Colour _col; // 节点颜色(RED / BLACK)
};
他们互相的详情映射关系就是这样 这里通过仿函数完美解决了
map、set第二个参数不同的问题 :
2. 迭代器的模拟实现
iterator实现的大框架跟list的iterator思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现,迭代器像指针一样访问的行为。
这一块还是比较基础简单的(毕竟能看到这我相信基础STL的模拟实现起码是十分熟练的)
cpp
// 红黑树迭代器:支持中序遍历(左 → 根 → 右),符合 STL 迭代器规范
template<class T, class Ref, class Ptr>
//Ref 相当于引用
//Ptr 可以相当于指针
struct TreeIterator
{
typedef RBTreeNode<T> Node; // 节点类型别名
typedef TreeIterator<T, Ref, Ptr> Self; // 当前迭代器类型别名
Node* _node; // 指向当前节点的指针
// 构造函数:用一个节点指针初始化迭代器(可用于 begin() 或 end())
TreeIterator(Node* node)
: _node(node)
{}
// 解引用操作符 *it → 返回当前节点数据的引用
Ref operator*()
{
return _node->_data;
}
// 成员访问操作符 it-> → 返回当前节点数据的地址(用于访问成员,如 kv.first)
Ptr operator->()
{
return &_node->_data;
}
// 不等于比较:用于 for 循环或算法中的终止判断(如 it != tree.end())
bool operator!=(const Self& s) const
{
return _node != s._node;
}
};
这里唯一我觉得可能有问题的就是这一段:
cpp
// 成员访问操作符 it-> → 返回当前节点数据的地址(用于访问成员,如 kv.first)
Ptr operator->()
{
return &_node->_data;
}
这涉及到一个知识点 我们假设it为map迭代器 it->second 这其实相当于&(it->_node->data)->second这里是为了美观省略成一个-> 这里大概提一下 具体自己可以搜一下详细资料。
这里的难点是 operator++ 和 operator-- 的实现。之前使用部分,我们分析了,map 和 set 的迭代器走的是中序遍历,左子树 -> 根结点 -> 右子树,那么 begin () 会返回中序第一个结点的 iterator 也就是 10 所在结点的迭代器。
| 迭代器相关内容 | 具体规则 |
|---|---|
| 迭代器遍历方式 | 中序遍历(左子树→根结点→右子树),begin()返回中序首个结点(如10) |
| 迭代器++(右子树非空) | 下一个结点:当前结点右子树的最左结点(右子树的中序首个结点) |
| 迭代器++(右子树为空) | 沿祖先路径向上找: 1. 若当前是父亲的左孩子 → 下一个是父亲 2. 若当前是父亲的右孩子 → 继续向上,直到找到"孩子为左的祖先" |
| ⚠️: | 我们要抓住 只看重当前节点这一个原则!! |
cpp
// 前置自增:++it,将迭代器移动到中序遍历的下一个节点
Self& operator++()
{
// 中序遍历顺序:左子树 → 当前节点 → 右子树
// 因此,"下一个"节点取决于当前节点是否有右子树
// 情况1:当前节点有右子树
// → 中序后继一定是右子树中的最左节点(即右子树的最小值)
if (_node->_right)
{
Node* min = _node->_right; // 进入右子树
while (min->_left) // 一直向左走到尽头
{
min = min->_left;
}
_node = min; // 更新迭代器指向该最左节点
}
// 情况2:当前节点没有右子树
// → 需要向上回溯,找到第一个"作为左孩子"的祖先节点,
// 该祖先节点就是中序后继
else
{
Node* cur = _node; // 从当前节点开始向上走
Node* parent = cur->_parent;
// 循环条件:
// - parent 存在(未到根以上)
// - 且当前节点是其父节点的右孩子(说明父节点已在中序中被访问过)
// 继续向上,直到找到一个祖先,使得当前路径是从其左子树上来
while (parent && cur == parent->_right)
{
cur = parent; // 向上移动
parent = parent->_parent; // 继续找更高层祖先
}
// 循环结束时:
// - 若 parent != nullptr,则 parent 就是中序后继(cur 是 parent 的左子树中的节点)
// - 若 parent == nullptr,说明当前节点是整棵树的最右节点,++ 后应为 end()(通常用 nullptr 表示)
_node = parent;
}
// 返回自增后的迭代器引用(符合前置++语义)
return *this;
}
这里 -- 因为篇幅原因 就不独立实现了!!
接下来
map和set就只需要调用对应接口就可以了!这里我们可以实现const_iterator和iterator两种形式。
红黑树:
cpp
// 定义普通迭代器:可修改值(但不能改 key,因 T 中 key 为 const)
typedef TreeIterator<T, T&, T*> Iterator;
// 定义常量迭代器:不可修改任何内容
typedef TreeIterator<T, const T&, const T*> Const_Iterator;
// 返回指向中序第一个元素(最左节点)的迭代器
Iterator Begin()
{
Node* min = _root;
while (min && min->_left)
{
min = min->_left;
}
return Iterator(min);
}
// 返回 end() 迭代器(通常用 nullptr 表示"末尾之后")
Iterator End()
{
return Iterator(nullptr);
}
// const 版本的 Begin()
Const_Iterator Begin() const
{
Node* min = _root;
while (min && min->_left)
{
min = min->_left;
}
return Const_Iterator(min);
}
// const 版本的 End()
Const_Iterator End() const
{
return Const_Iterator(nullptr);
}
map&&set
cpp
// 定义迭代器类型
// 注意:set 中所有元素都是 const(不可修改),因此底层红黑树存储的是 const K
typedef typename RBTree<K, const K, SetKeyOfT>::Iterator iterator;
// 在标准库中,set 的普通迭代器应具有 const 行为(即不能通过迭代器修改 key)
// 此处将 const_iterator 也定义为同一种类型(实际更严谨的做法是区分,但常见简化处理)
typedef typename RBTree<K, const K, SetKeyOfT>::Iterator const_iterator;
// 返回指向第一个元素的迭代器(中序最左节点)
iterator begin()
{
return _t.Begin();
}
// 返回 end() 迭代器(通常对应 nullptr)
iterator end()
{
return _t.End();
}
// const 版本的 begin()
const_iterator begin() const
{
return _t.Begin();
}
// const 版本的 end()
const_iterator end() const
{
return _t.End();
}
-----------------------------------------------------------------------------------
// 定义迭代器类型:使用红黑树中已定义的 Iterator
// 节点存储类型为 pair<const K, V>:
// - key 为 const:防止用户通过迭代器修改 key(破坏树结构)
// - value 为 V:允许通过 it->second 修改 value
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Iterator iterator;
// 定义常量迭代器类型:只读访问
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Const_Iterator const_iterator;
// 非 const 版本 begin():返回指向最左节点(最小 key)的迭代器
iterator begin()
{
return _t.Begin();
}
// 非 const 版本 end():返回"末尾之后"的迭代器(通常为 nullptr 封装)
iterator end()
{
return _t.End();
}
// const 版本 begin():用于 const map 对象,返回 const_iterator
const_iterator begin() const
{
return _t.Begin(); // 调用红黑树的 const Begin()
}
// const 版本 end()
const_iterator end() const
{
return _t.End(); // 调用红黑树的 const End()
}
这里还有个易错的注意点:
typedef typename RBTree<K, pair<const K, V>, MapKeyOfT>::Const_Iterator const_iterator;很多人会不小心写成
typedef typename RBTree<K, pair<const K, const V>, MapKeyOfT>::Const_Iterator const_iterator这么写会造成模版参数不匹配的问题RBTree的模版参数是RBTree<K,pair<const K,V>,MapKeyOfT>_t;
还有个易忘点:
typename是 C++ 模板编程中的一个关键字,主要用于在依赖于模板参数的上下文中,告诉编译器某个名字是一个类型名(type name),而不是变量、函数或其他东西。
| 场景 | 是否需要 typename |
|---|---|
vector<T>::iterator |
✅ 需要(依赖于 T) |
MyClass::NestedType(MyClass 不依赖模板参数) |
❌ 不需要 |
T::value_type(T 是模板参数) |
✅ 需要 |
| 函数返回类型(C++11 之前) | ✅ 需要 (C++14+ 在 auto 推导中可省略) |
3. Insert的实现
这里insetr 功能的实现 我们只需要修改 红黑树里面的insert 就可以了
其实这里面实际需要修改的东西并不多 只需要将返回值进行修改然后对里面一些参数进行微调(利用仿函数 针对map&&set两种不同情况)
cpp
pair<iterator,bool> Insert(const T& data)
- T:红黑树中存储的实际数据类型(如 pair)。
- 返回值:
- Iterator:指向插入节点(或已存在节点)的迭代器。
- bool:true 表示成功插入,false 表示 key 已存在(未插入)。
然后就是再补上仿函数和修改一下返回值信息即可
为邻方便大家比较,截取了一部分:
修改前:
修改后:
完整代码:
cpp
// 插入函数:返回 {迭代器, 是否插入成功}
pair<Iterator, bool> Insert(const T& data)
{
// 情况1:空树 → 直接创建根节点,并设为黑色(红黑树性质:根必须为黑)
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return { Iterator(_root), true };
}
// 创建 Key 提取器(用于比较)
KeyOfT kot;
Node* parent = nullptr;
Node* cur = _root;
// 查找插入位置(类似 BST 插入)
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
{
// key 已存在 → 插入失败,返回已存在节点的迭代器
return { Iterator(cur), false };
}
}
// 创建新节点(默认红色)
cur = new Node(data);
Node* newnode = cur;
cur->_col = RED;
cur->_parent = parent;
// 将新节点链接到父节点
if (kot(parent->_data) < kot(data))
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
// ===== 红黑树插入后调整(核心:修复可能违反的红黑性质)=====
// 红黑树性质要求:
// 1. 节点是红或黑
// 2. 根是黑
// 3. 红节点的孩子必须是黑(不能有两个连续红节点)
// 4. 从任一节点到其所有叶子的路径包含相同数量的黑节点(黑高一致)
// 调整循环:只要父节点存在且为红色(违反性质3),就需要处理
while (parent && parent->_col == RED)
{
Node* grandfather = parent->_parent; // 祖父节点(必存在,因为 parent 是红 → 不可能是根)
// 情况A:父亲是祖父的左孩子
if (grandfather->_left == parent)
{
Node* uncle = grandfather->_right; // 叔叔节点(祖父的右孩子)
// 子情况A1:叔叔存在且为红色 → 变色(父、叔变黑,祖父变红),继续向上处理
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col = RED;
// 继续以祖父为"当前节点"向上检查
cur = grandfather;
parent = cur->_parent;
}
// 子情况A2:叔叔不存在或为黑色 → 需要旋转 + 变色
else
{
// 子子情况A2a:当前节点是父节点的左孩子 → 右单旋(LL 型)
if (cur == parent->_left)
{
RotateR(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
// 子子情况A2b:当前节点是父节点的右孩子 → 左右双旋(LR 型)
else
{
RotateL(parent);
RotateR(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break; // 调整后满足性质,退出循环
}
}
// 情况B:父亲是祖父的右孩子(对称处理)
else // grandfather->_right == parent
{
Node* uncle = grandfather->_left; // 叔叔节点(祖父的左孩子)
if (uncle && uncle->_col == RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
// 子子情况B2a:当前节点是父节点的右孩子 → 左单旋(RR 型)
if (cur == parent->_right)
{
RotateL(grandfather);
parent->_col = BLACK;
grandfather->_col = RED;
}
// 子子情况B2b:当前节点是父节点的左孩子 → 右左双旋(RL 型)
else
{
RotateR(parent);
RotateL(grandfather);
cur->_col = BLACK;
grandfather->_col = RED;
}
break;
}
}
}
// 无论是否进入循环,最后都确保根为黑色(性质2)
_root->_col = BLACK;
return { Iterator(newnode), true };
}
4. map的【】实现

这设计到STL里面
map的[]的底层原理 具体原理请参考我写的map的使用【点击转跳】
cpp
// operator[]:支持"插入或访问"语义
// - 若 key 存在:返回对应 value 的引用
// - 若 key 不存在:插入 {key, V()}(默认构造值),并返回该 value 的引用
V& operator[](const K& key)
{
// 尝试插入一个 pair,包含 key 和 V 类型的默认构造值
// 调用 insert 方法,它会尝试将 {key, V()} 插入到红黑树中
// 返回值是一个 pair<iterator, bool>:
// - iterator 指向插入点或已存在的元素
// - bool 表示是否成功插入新节点 (true 表示插入成功,false 表示 key 已存在)
pair<iterator, bool> ret = insert({ key, V() });
// 解析返回的 pair:
// - 如果 ret.second == true,说明是新插入的节点
// - 如果 ret.second == false,说明 key 已存在,指向的是现有节点
// ret.first 是一个迭代器,指向了包含所需 key 的节点
// 对于 map 中存储的数据类型 pair<const K, V>,通过 ->second 可以访问和修改 value 部分
// 注意:即使 key 已存在,这里也直接返回了对应的 value 引用,允许后续修改
return ret.first->second;
}
5.完整代码
5.1 <红黑.h>
cpp
//
// 红黑.h
// 红黑树
//
// Created by Fanz on 2025/12/30.
//
#pragma once
// 枚举值表示颜色
using namespace std;
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
// 这里更新控制平衡也要加入parent指针
T _data;
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
Colour _col;
RBTreeNode(const T& data)
:_data(data)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
{}
};
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) const
{
return _node!=s._node;
}
// 前置自增:++it,将迭代器移动到中序遍历的下一个节点
Self& operator++()
{
// 中序遍历顺序:左子树 → 当前节点 → 右子树
// 因此,"下一个"节点取决于当前节点是否有右子树
// 情况1:当前节点有右子树
// → 中序后继一定是右子树中的最左节点(即右子树的最小值)
if (_node->_right)
{
Node* min = _node->_right; // 进入右子树
while (min->_left) // 一直向左走到尽头
{
min = min->_left;
}
_node = min; // 更新迭代器指向该最左节点
}
// 情况2:当前节点没有右子树
// → 需要向上回溯,找到第一个"作为左孩子"的祖先节点,
// 该祖先节点就是中序后继
else
{
Node* cur = _node; // 从当前节点开始向上走
Node* parent = cur->_parent;
// 循环条件:
// - parent 存在(未到根以上)
// - 且当前节点是其父节点的右孩子(说明父节点已在中序中被访问过)
// 继续向上,直到找到一个祖先,使得当前路径是从其左子树上来
while (parent && cur == parent->_right)
{
cur = parent; // 向上移动
parent = parent->_parent; // 继续找更高层祖先
}
// 循环结束时:
// - 若 parent != nullptr,则 parent 就是中序后继(cur 是 parent 的左子树中的节点)
// - 若 parent == nullptr,说明当前节点是整棵树的最右节点,++ 后应为 end()(通常用 nullptr 表示)
_node = parent;
}
// 返回自增后的迭代器引用(符合前置++语义)
return *this;
}
};
template<class K, class T, class KeyOfT>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
typedef TreeIterator<T,T&,T*> Iterator;
typedef TreeIterator<T,const T&,const T*> Const_Iterator;
Iterator Begin()
{
Node* min= _root;
while (min&&min->_left)
{
min=min->_left;
}
return Iterator(min);
}
Iterator End()
{
return Iterator(nullptr);
}
Const_Iterator Begin() const
{
Node* min= _root;
while (min&&min->_left)
{
min=min->_left;
}
return Const_Iterator(min);
}
Const_Iterator End() const
{
return Const_Iterator(nullptr);
}
pair<Iterator, bool> Insert(const T& data)
{
if (_root == nullptr)
{
_root = new Node(data);
_root->_col = BLACK;
return {Iterator(_root),true};
}
KeyOfT kot;
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 {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* grandfather = parent->_parent;
if (grandfather->_left==parent) //父亲在左
{
Node* uncle = grandfather->_right;
//叔叔存在且为红 变色即可
if (uncle&&uncle->_col==RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col=RED;
//继续往上处理
cur = grandfather;
parent =cur->_parent;
}
else //叔叔不存在,或者叔叔存在且为黑
{
// g
// p u
//c
//右单旋
if(cur==parent->_left)//如果cur等于父亲的左边
{
RotateR(grandfather);
parent->_col=BLACK;
grandfather->_col=RED;
}
else
{
// g
//p u
// c
//左右双旋
RotateL(parent);
RotateR(grandfather);
cur->_col=BLACK;
grandfather->_col=RED;
}
break;
}
}
else //父亲在右 grandfather->_right == parent
{
Node* uncle = grandfather->_left;
//叔叔存在且为红 变色即可
if (uncle&&uncle->_col==RED)
{
parent->_col = BLACK;
uncle->_col = BLACK;
grandfather->_col=RED;
//继续往上处理
cur = grandfather;
parent =cur->_parent;
}
else //叔叔不存在,或者叔叔存在且为黑
{
// g
// u p
// c
//左单旋
if(cur==parent->_right)//如果cur等于父亲的左边
{
RotateL(grandfather);
parent->_col=BLACK;
grandfather->_col=RED;
}
else
{
// g
//u p
// c
//左右双旋
RotateR(parent);
RotateL(grandfather);
cur->_col=BLACK;
grandfather->_col=RED;
}
break;
}
}
}
//最简单处理根的方式 循环结束后不做判断 直接把根变成黑的
_root->_col=BLACK;
return {Iterator(newnode),true};
}
private:
Node* _root = nullptr;
//copy的AVL树代码
void RotateR(Node* parent)
{
//结合图1 看代码 不然脑子一团浆糊
Node* subL =parent->_left;
Node* subLR =subL->_right;
parent->_left = subLR;
//注意 subLR可能为空
if(subLR)
subLR->_parent=parent;
//如果调整的是局部子树 所以最好纪录下parent的parent
Node* parentParent = parent->_parent;
subL->_right=parent;
parent->_parent=subL;
//如果parent是根节点
if (parent == _root)
{
_root=subL;
subL->_parent=nullptr;
}
else
{
// 如果调整的是局部子树
if(parentParent->_left==parent)
{
parentParent->_left=subL;
}
else
{
parentParent->_right=subL;
}
subL->_parent=parentParent;
}
}
void RotateL(Node* parent)
{
Node* subR=parent->_right;
Node* subRL=subR->_left;
parent->_right=subRL;
//防止subRL为空
if (subRL)
subRL->_parent=parent;
Node* parentParent=parent->_parent;
subR->_left=parent;
parent->_parent=subR;
if (parent==_root)
{
_root=subR;
subR->_parent=nullptr;
}
else
{
// 如果调整的是局部子树
if(parentParent->_left==parent)
{
parentParent->_left=subR;
}
else
{
parentParent->_right=subR;
}
subR->_parent=parentParent;
}
}
};
5.2 <set.h>
cpp
//
// set.h
// map和set封装
//
// Created by Fanz on 2026/1/3.
//
#pragma once
#include"红黑.h"
namespace fcy
{
template<class K>
class set
{
struct SetKeyOfT
{
const K& operator()(const K& key)
{
return key;
}
};
public:
typedef typename RBTree<K,const K, SetKeyOfT>::Iterator iterator;
typedef typename RBTree<K,const K, SetKeyOfT>::Iterator const_iterator;
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
const_iterator begin() const
{
return _t.Begin();
}
const_iterator end() const
{
return _t.End();
}
pair<iterator, bool> insert(const K& k)
{
return _t.Insert(k);
}
private:
RBTree<K,const K,SetKeyOfT> _t; //第二个模版参数决定存什么
};
}
5.3 <map.h>
cpp
//
// map.h
// map和set封装
//
// Created by Fanz on 2026/1/3.
//
#pragma once
#include"红黑.h"
namespace fcy
{
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<const K,V>, MapKeyOfT>::Iterator iterator;
typedef typename RBTree<K,pair<const K,V>, MapKeyOfT>::Const_Iterator const_iterator;
iterator begin()
{
return _t.Begin();
}
iterator end()
{
return _t.End();
}
const_iterator begin() const
{
return _t.Begin();
}
const_iterator end() const
{
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({key,V()});
return ret.first->second;
}
private:
RBTree<K,pair<const K,V>,MapKeyOfT>_t;
};
}
5.4 测试样例代码
cpp
//
// main.cpp
// map和set封装
//
// Created by Fanz on 2026/1/3.
//
#include <iostream>
#include <utility>
#include "map.h"
#include "set.h"
using namespace std;
void test_set()
{
fcy::set<int> s;
s.insert(4);
s.insert(1);
s.insert(2);
s.insert(12);
s.insert(22);
s.insert(2223);
s.insert(-2);
s.insert(0);
fcy::set<int>::iterator it = s.begin();
while (it != s.end())
{
// *it = 1;
cout << *it << " ";
++it;
}
cout << endl;
}
void test_map()
{
fcy::map<string, string> dict;
dict.insert({ "sort", "排序" });
dict.insert({ "left", "左边" });
dict.insert({ "right", "右边" });
dict["left"] = "左边,剩余"; // 修改
dict["insert"] = "插入"; // 插入+修改
dict["string"]; // 插入
fcy::map<string, string>::iterator it = dict.begin();
while (it != dict.end())
{
// 不能修改first,可以修改second
//it->first += 'x';
//it->second += 'x';
cout << it->first << ":" << it->second << endl;
++it;
}
cout << endl;
}
int main()
{
test_set();
test_map();
return 0;
}





