概念:
红黑树 是一种二叉搜索树 每个节点上增加一个存储位置代表节点颜色 可以是 红 / 黑
通过对任何一条从根到叶子路径各个节点 进行限制,确保任何一条路径比最短路径长两倍
故接近平衡
性质| 左根右,根叶黑,不红红,黑路同
每个节点不是红就是黑
根节点是黑色
如果一个节点是 红色的 则两孩子 是 黑色的
对于每个节点到后代节点的 简单路径下 都包含相同数目的黑色节点
每个叶子空节点为黑色
红黑树平衡的原理是什么 ?
它通过每个节点上的颜色属性(红色或黑色)来确保树在插入和删除操作后仍然保持大致平衡。
当进行插入和删除操作时,红黑树会通过重新着色和旋转节点来调整树的结构,以保持上述性质
性质3保证了防止出现连续的红色节点会使路径差距太大
性质4保证了保任何一条路径比最短路径长两倍
红黑树能够在插入和删除操作后快速重新平衡,保持其搜索效率。红黑树的搜索、插入和删除操作的时间复杂度都是O(log n)
红黑树的插入操作
按照二叉搜索树的顺序进行插入数据
新节点插入后 查看红黑树的性质是否遭到破坏
插入新节点后 颜色默认为红色 ,如果双亲的节点的颜色是黑色 没有违反红黑树任何的性质 故不需要调整
如果插入后节点的颜色为红 双亲节点也是红色 就违反了第三条性质 需要分情况讨论
情况1. cur 为🔴 p 为🔴 g为⚫ u存在且为 🔴
解决方法 将 p,u 改为⚫ g 改为🔴 如果 g为根节点 将g改回⚫ 否则 将g 当作Cur 继续网上调整
情况2. cur 为🔴 p为🔴 g为 ⚫ u不存在/ u存在且为⚫
2.1 如果u 节点 不存在 则 Cur 一定是新插入的节点 如果 Cur 不是新插入节点则Cur 和p一定有一个节点的颜色是黑色 则不满足路径的黑色节点树相同
2.2 如果u 节点存在 则其 一定是黑色那么 Cur 原来的颜色一定是黑色的
3 cur 为红 p为红 g 为黑 u不存在/u存在且为黑
红黑树的调节关键看叔叔节点
代码参考
#pragma once
#include <iostream>
#include <algorithm>
using namespace std;
namespace chen{
enum Color {
BLACK,
RED
};
template <class K,class V>
class RBTreeNode {
public:
RBTreeNode(const pair<K, V>& _val)
: _left(nullptr), _right(nullptr), _parent(nullptr), _kv(_val), _col(RED) // 初始化新节点为红色
{}
RBTreeNode<K, V>* _left; // 左子节点
RBTreeNode<K, V>* _right; // 右子节点
RBTreeNode<K, V>* _parent; // 父节点
pair<K, V> _kv; // 键值对
Color _col; // 节点颜色
};
template <class K,class V>
class RBTree {
typedef RBTreeNode<K,V> Node;
public:
bool insert(const pair<K,V> & val) {
// 按照搜索树的顺序进行插入
if(_root == nullptr) {
_root = new Node(val);
_root->_col = BLACK;
return true;
}
Node * Cur = _root;
Node * parent = nullptr;
while(Cur) {
if(Cur->_kv.first < val.first) {
parent = Cur;
Cur = Cur->_right;
}else if(Cur->_kv.first > val.first) {
parent = Cur;
Cur = Cur->_left;
}else {
return false;
// 有相同的 K
}
}
Cur = new Node(val);
Cur->_col = RED; // 新增节点 颜色是RED
Cur->_parent = parent;
if(parent->_kv.first < val.first) {
parent->_right = Cur;
}else {
parent->_left = Cur;
}
while(parent && parent->_col == RED) {
Node * grandfather = parent->_parent;
if(grandfather->_left == parent) {
Node * uncle = grandfather->_right;
if(uncle && uncle->_col == RED) {
// 情况一 uncle 存在且为红
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续处理
Cur = grandfather;
parent = Cur->_parent;
}
else {
//情况三 uncle 存在 且为黑
//情况二 uncle 不存在
if(Cur == parent->_right) {
rotateL(parent);
swap(parent , Cur);
}
// 第三种情况 有可能是 第二种变回来的
rotateR(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
break;
}
}else {
Node * uncle = grandfather->_left;
if(uncle && uncle->_col == RED) {
// 情况1
parent->_col = uncle->_col = RED;
grandfather->_col = RED;
// 继续处理
Cur = grandfather;
parent = Cur->_parent;
}else {
if(Cur == parent->_left) {
rotateR(parent);
swap(parent,grandfather);
}
rotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
break;
}
}
}
_root->_col = BLACK; // 最后根都是黑色
return true;
}
void InOrder()
{
_InOrder(_root);
}
private:
Node * _root = nullptr;
void rotateL(Node * parent) {
Node * New_parent = parent->_right;
parent->_right = New_parent->_left;
if(New_parent->_left) {
New_parent->_left->_parent = parent;
}
New_parent->_left = parent;
New_parent->_parent = parent->_parent;
if(parent->_parent == nullptr) {
_root = New_parent;
}else if(New_parent->_parent->_left == parent) {
parent->_parent->_left = New_parent;
}else {
parent->_parent->_right = New_parent;
}
parent->_parent = New_parent;
}
void rotateR(Node * parent) {
Node * New_parent = parent -> _left;
parent->_left = New_parent->_right;
New_parent->_left = parent;
New_parent->_parent = parent->_parent;
if(parent->_parent == nullptr) {
_root = New_parent;
}else if(parent->_parent->_left == parent) {
parent->_parent->_left = New_parent;
}else {
parent->_parent->_right = New_parent;
}
parent->_parent = New_parent;
}
void _InOrder(Node * root)
{
if(!root)return ;
_InOrder(root->_left);
cout << root->_kv.first <<" : " << root->_kv.second << " Color:" <<root->_col <<endl;
_InOrder(root->_right);
}
};
void testRBTree() {
RBTree<int,int> RBT;
RBT.insert({1,1});
RBT.insert({2,2});
RBT.insert({3,3});
RBT.insert({4,4});
RBT.insert({5,5});
RBT.insert({6,6});
RBT.insert({7,7});
RBT.insert({8,8});
RBT.insert({9,9});
RBT.InOrder();
}
}
红黑树的删除
红黑树的删除 分为四种情况
删除节点为叶子节点
删除节点只有左孩子,没有右孩子
删除节点只有右孩子,没有左孩子
删除节点 既有右孩子 又有左孩子
删除节点为叶子节点
如果删除节点叶子节点D为红节点 则直接删除红节点
如果删除节点叶子节点D为黑节点
要删除节点的叶子节点为黑色,D的兄弟节点也为黑色,没有侄子节点.
删除D节点 将P节点变为黑色 将B节点变为白色
要删除节点D为黑色 D的兄弟节点B也为黑色 ,D的左侄子为红色
删除 D 节点 将B左侄子进行右旋 ,将左侄子变为P的颜色将P变为黑色,再 按照 P 进行左旋
要删除节点D为黑色 D的兄弟节点B也为黑色 ,D的右侄子为红色
删除D节点 B 变成P 的颜色 P和右侄子的颜色变成黑色 再按照左旋操作
要删除节点D为黑色 D的兄弟节点B也为黑色 ,D的右侄子和左侄子为红色
先删除D节点 按着P 进行左旋操作 将B变成P 的颜色将P和右侄子变成黑色
要删除的叶子节点D为黑色,D的兄弟节点B为红色 D的左侄子和右侄子为黑色
先将D节点删除 按照P 节点左旋 将B 变成黑色 将左侄子变成红色
删除节点只有左孩子,没有右孩子
将D的值 变成 左侄子的值 删除左侄子
删除节点D只有右孩子 ,没有左孩子,和情况而一样
将D的值变成 右侄子的值 删除右侄子
删除节点D 既有右孩子也有左孩子
将D节点的值 转换成 D节点前驱节点的值
删除前驱节点 传换成前三种情况
暂未实现😭
搞太久了
模拟实现map|set
在stl中的map 源码 和 set 的源码框架中 为了防止代码冗余其中 Map 和 set 都是使用的同一棵红黑树
如何使用一棵红黑树实现出Map和set?
Map.h
#pragma once
#include "RBTree.h"
namespace chen
{
template<class K, class V>
class map
{
struct KOV
{
const K& operator()(const pair<const K, V>& kv)
{
return kv.first;
}
};
public:
typedef typename RBTree<K, pair<K, V>, KOV>::iterator iterator;
bool insert(const pair<const K, V>& kv)
{
return _t.insert(kv);
}
iterator begin() {
return iterator(_t.begin());
}
iterator end() {
return iterator(_t.end());
}
private:
RBTree<K, pair<K, V>, KOV> _t;
};
void test_map1()
{
map<int, int> m;
m.insert(make_pair(1, 10));
m.insert(make_pair(3, 30));
m.insert(make_pair(2, 20));
for(auto &i:m){
cout << i.first <<":" << i.second << endl;
}
}
}
Set.h
#pragma once
#include "RBTree.h"
namespace chen {
template<class K>
class set {
struct KOV {
const K& operator()(const K& key) {
return key;
}
};
public:
typedef typename RBTree<K, K, KOV>::iterator iterator;
// begin和end明确指定typename
iterator begin() {
return iterator(_t.begin());
}
iterator end() {
return iterator(_t.end());
}
bool insert(const K& key) {
return _t.insert(key);
}
private:
RBTree<K, K, KOV> _t;
};
void test_set1() {
set<int> s;
s.insert(3);
s.insert(1);
s.insert(2);
set<int>::iterator it = s.begin();
while (it != s.end()) {
cout << *it << " ";
++it;
}
cout << endl;
}
}
RBTree.h
#pragma once
#include <iostream>
#include <algorithm>
using namespace std;
namespace chen{
enum Color {
BLACK,
RED
};
template <class T>
struct RBTreeNode {
RBTreeNode(const T& data)
: _left(nullptr), _right(nullptr), _parent(nullptr), _data(data), _col(RED) // 初始化新节点为红色
{}
RBTreeNode<T>* _left; // 左子节点
RBTreeNode<T>* _right; // 右子节点
RBTreeNode<T>* _parent; // 父节点
T _data; // data Key
Color _col; // 节点颜色
};
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){
return _node!=s._node;
}
Self& operator++() {
if (_node->_right) {
// 右子树存在,找到右子树中的最左节点
Node *subLeft = _node->_right;
while (subLeft->_left) {
subLeft = subLeft->_left;
}
_node = subLeft; // 更新当前节点
} else {
// 无右子树,向上找到第一个不为右子节点的父节点
Node *parent = _node->_parent;
while (parent && _node == parent->_right) {
_node = parent;
parent = parent->_parent;
}
_node = parent; // 更新当前节点为其父节点
}
return *this;
}
};
// template <class K,class V>
template <class K,class T,class KeyOfvalue>
class RBTree {
// typedef RBTreeNode<K,V> Node;
// typedef __RBTreeIterator<T,const T&,const T*> const_iterator
public:
typedef __RBTreeIterator<T,T&,T*> iterator;
typedef RBTreeNode<T> Node;
iterator begin(){
Node * cur = _root;
while(cur && cur->_left){
cur = cur->_left;
}
return iterator(cur);
}
iterator end(){
return iterator(nullptr);
}
////////////////////////////////////////////////////////////////////////////
bool insert(const T& val) {
// 按照搜索树的顺序进行插入
if(_root == nullptr) {
_root = new Node(val);
_root->_col = BLACK;
return true;
}
KeyOfvalue KOV;
Node * Cur = _root;
Node * parent = nullptr;
while(Cur) {
if(KOV(Cur->_data) < KOV(val)) {
parent = Cur;
Cur = Cur->_right;
}else if(KOV(Cur->_data) > KOV(val)) {
parent = Cur;
Cur = Cur->_left;
}else {
return false;
// 有相同的 K
}
}
Cur = new Node(val);
Cur->_col = RED; // 新增节点 颜色是RED
Cur->_parent = parent;
if(KOV(parent->_data) < KOV(val)) {
parent->_right = Cur;
}else {
parent->_left = Cur;
}
while(parent && parent->_col == RED) {
Node * grandfather = parent->_parent;
if(grandfather->_left == parent) {
Node * uncle = grandfather->_right;
if(uncle && uncle->_col == RED) {
// 情况一 uncle 存在且为红
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
// 继续处理
Cur = grandfather;
parent = Cur->_parent;
}
else {
//情况三 uncle 存在 且为黑
//情况二 uncle 不存在
if(Cur == parent->_right) {
rotateL(parent);
swap(parent , Cur);
}
// 第三种情况 有可能是 第二种变回来的
rotateR(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
break;
}
}else {
Node * uncle = grandfather->_left;
if(uncle && uncle->_col == RED) {
// 情况1
parent->_col = uncle->_col = RED;
grandfather->_col = RED;
// 继续处理
Cur = grandfather;
parent = Cur->_parent;
}else {
if(Cur == parent->_left) {
rotateR(parent);
swap(parent,grandfather);
}
rotateL(grandfather);
grandfather->_col = RED;
parent->_col = BLACK;
break;
}
}
}
_root->_col = BLACK; // 最后根都是黑色
return true;
}
void InOrder()
{
_InOrder(_root);
}
private:
Node * _root = nullptr;
void rotateL(Node* parent) {
Node* newParent = parent->_right;
if(!newParent)return ;
parent->_right = newParent->_left;
if (newParent->_left) {
newParent->_left->_parent = parent;
}
newParent->_parent = parent->_parent;
if (parent->_parent == nullptr) {
_root = newParent; // 更新根节点
} else if (parent == parent->_parent->_left) {
parent->_parent->_left = newParent;
} else {
parent->_parent->_right = newParent;
}
newParent->_left = parent;
parent->_parent = newParent;
}
void rotateR(Node* parent) {
Node* newParent = parent->_left;
parent->_left = newParent->_right;
if (newParent->_right) {
newParent->_right->_parent = parent;
}
newParent->_parent = parent->_parent;
if (parent->_parent == nullptr) {
_root = newParent; // 更新根节点
} else if (parent == parent->_parent->_left) {
parent->_parent->_left = newParent;
} else {
parent->_parent->_right = newParent;
}
newParent->_right = parent;
parent->_parent = newParent;
}
};