红黑树是对于二叉搜索树除了AVL数外的另一种改进,对节点引入额外的颜色变量,通过对颜色规则的控制,保证树的最长路径不超过最短路径的二倍
1.红黑树的规则
1.所有节点的颜色不是红色就是黑色
2.根节点为黑色
3.红色节点的孩子节点不可为红色,也就是不能出现连续的红色节点
4.每条路径(从根节点到空节点)的黑色节点数量保持一致
2.红黑树查询的时间复杂度
设最短路径高为h,则总节点数 n 满足 (2^h) - 1<= n < (2^2h)-1,h大致为2logn,即搜索的时间复杂度仍为o(logn)
3.红黑树的插入
若插入的节点为根节点,则插入为黑色节点,其余插入为红色节点
插入结点后向上对红黑树进行检查与调整
若父节点是黑色节点,停止检查,插入完毕
若父节点是红色节点,则主要看父亲的兄弟节点,也就是叔叔节点的情况
1.只变色的情况
插入或变化节点的叔叔节点存在且为红色,则仅需把父亲节点的父亲节点,即爷爷节点变为红色,将父亲和叔叔节点变为黑色,就像爷爷节点的黑色流动下来了一样,然后将爷爷节点作为变化的节点继续向上检测更新,若爷爷节点是根节点,将根节点再变回黑色,插入结束
2.变化颜色 + 单旋的情况
插入或变化的节点在父节点左侧,父节点在爷爷节点左侧,叔叔节点为黑或不存在,对爷爷节点右单旋
插入或变化的节点在父节点右侧,父节点在爷爷节点右侧,叔叔节点为黑或不存在,对爷爷节点左单旋
关于旋转不会的可以看我AVL树的博客:C++数据结构之二叉搜索树和AVL树-优快云博客
3.变化颜色 + 双旋的情况
插入或变化的节点在父节点右侧,父节点在爷爷节点左侧,叔叔节点为黑或不存在,对爷爷节点左右双旋
插入或变化的节点在父节点左侧,父节点在爷爷节点右侧,叔叔节点为黑或不存在,对爷爷节点右左双旋
以上便是红黑树插入的三种情况
4.红黑树的代码实现
#include<iostream>
using namespace std;
enum Color
{
red,
black
};
template<class T>
struct RBTreeNode
{
RBTreeNode(const T& data = T())
: _pLeft(nullptr)
, _pRight(nullptr)
, _pParent(nullptr)
, _data(data)
, _col(red)
{}
RBTreeNode<T>* _pLeft;
RBTreeNode<T>* _pRight;
RBTreeNode<T>* _pParent;
T _data;
Color _col;
};
// 为方便构建,先注释掉head节点,以root节点为准
template<class T>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
RBTree() :_pRoot(nullptr)
{
/*
_pHead = new Node;
_pHead->_pLeft = _pHead;
_pHead->_pRight = _pHead;
*/
}
~RBTree()
{
destoryTree(_pRoot);
}
// 在红黑树中插入值为data的节点,插入成功返回true,否则返回false
// 注意:为了简单起见,本次实现红黑树不存储重复性元素
bool Insert(const T& data)
{
//先按二叉搜索树逻辑插入
if (_pRoot == nullptr)
{
_pRoot = new Node;
_pRoot->_data = data;
_pRoot->_col = black;
return true;
}
Node* cur = _pRoot;//cur为节点插入位置
Node* curParent = nullptr;
while (cur->_data != data)
{
if (cur->_data > data)
{
curParent = cur;
cur = curParent->_pLeft;
}
else
{
curParent = cur;
cur = curParent->_pRight;
}
if (cur == nullptr)
{
//发现可插入位置,将新节点给cur,并插于curParent下,将curParent平衡因子更新
cur = new Node;
cur->_data = data;
cur->_pParent = curParent;
if (data < curParent->_data)
{
curParent->_pLeft = cur;
}
else
{
curParent->_pRight = cur;
}
}
}
//判断与父节点颜色是否匹配,若不匹配则进行平衡
while (cur->_col == red && curParent->_col == red)
{
Node* curGurand = curParent->_pParent;
Node* curUncle = nullptr;
if (curGurand->_pLeft == curParent)
{
curUncle = curGurand->_pRight;
}
else
{
curUncle = curGurand->_pLeft;
}
//只改颜色的情况
if (curUncle && curUncle->_col == red)
{
curGurand->_col = red;
curParent->_col = black;
curUncle->_col = black;
if (curGurand == _pRoot)
{
curGurand->_col = black;
break;
}
//以祖父节点为源继续检测
cur = curGurand;
curParent = cur->_pParent;
}
//旋转的情况
else
{
if (curGurand->_pLeft == curParent)
{
if (curParent->_pLeft == cur)
{
// g
// p u
// c
//右单旋
RotateR(curGurand);
curParent->_col = black;
curGurand->_col = red;
break;
}
else
{
// g
// p u
// c
//左右双旋
RotateLR(curGurand);
cur->_col = black;
curGurand->_col = red;
break;
}
}
else
{
if (curParent->_pRight == cur)
{
// g
//u p
// c
//左单旋
RotateL(curGurand);
curParent->_col = black;
curGurand->_col = red;
if (curGurand == _pRoot)
{
_pRoot = curParent;
}
break;
}
else
{
// g
//u p
// c
//右左双旋
RotateRL(curGurand);
cur->_col = black;
curGurand->_col = red;
if (curGurand == _pRoot)
{
_pRoot = cur;
}
break;
}
}
}
return true;
}
}
// 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
Node* Find(const T& data)
{
Node* cur = _pRoot;
while (cur)
{
if (cur->_data == data)
{
return cur;
}
else if (cur->_data > data)
{
cur = cur->_pLeft;
}
else
{
cur = cur->_pRight;
}
}
return nullptr;
}
// 获取红黑树最左侧节点
Node* LeftMost()
{
return _LeftMost(_pRoot);
}
// 获取红黑树最右侧节点
Node* RightMost()
{
return _RightMost(_pRoot);
}
// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
bool IsValidRBTRee()
{
rsize_t num = getBNum(_pRoot);
return _IsValidRBTRee(_pRoot,0,num);
}
//展示树
void showTree()
{
_showTree(_pRoot);
}
private:
Node* _LeftMost(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
if (root->_pLeft == nullptr)
{
return root;
}
return _LeftMost(root->_pLeft);
}
Node* _RightMost(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
if (root->_pRight == nullptr)
{
return root;
}
return _RightMost(root->_pRight);
}
bool _IsValidRBTRee(Node* pRoot, size_t blackCount, size_t pathBlack)
{
if (pRoot == nullptr)
{
return blackCount == pathBlack ? true : false;
}
if (pRoot->_col == black)
{
blackCount++;
}
return _IsValidRBTRee(pRoot->_pLeft,blackCount,pathBlack)&&_IsValidRBTRee(pRoot->_pRight,blackCount,pathBlack);
}
size_t getBNum(Node* root)
{
if (root == nullptr)
{
return 0;
}
if (root->_col == black)
return 1 + getBNum(root->_pLeft);
return getBNum(root->_pLeft);
}
// 左单旋
void RotateL(Node* pParent)
{
Node* pSonRight = pParent->_pRight;
Node* pGrand = pParent->_pParent;
pParent->_pRight = pSonRight->_pLeft;
if (pSonRight->_pLeft)
{
pSonRight->_pLeft->_pParent = pParent;
}
pParent->_pParent = pSonRight;
pSonRight->_pParent = pGrand;
pSonRight->_pLeft = pParent;
if (pGrand)
{
if (pGrand->_pLeft == pParent)
{
pGrand->_pLeft = pSonRight;
}
else
{
pGrand->_pRight = pSonRight;
}
}
/*pSonRight->_bf = 0;
pParent->_bf = 0;*/
//如果旋转节点为根节点还要对根节点进行更新
if (pParent == _pRoot)
{
_pRoot = pSonRight;
}
}
// 右单旋
void RotateR(Node* pParent)
{
Node* pSonLeft = pParent->_pLeft;
Node* pGrand = pParent->_pParent;
//将孩子的右节点给父母节点
pParent->_pLeft = pSonLeft->_pRight;
//右节点不为空还要改右节点的父母
if (pSonLeft->_pRight)
{
pSonLeft->_pRight->_pParent = pParent;
}
pParent->_pParent = pSonLeft;
pSonLeft->_pParent = pGrand;
pSonLeft->_pRight = pParent;
if (pGrand)
{
if (pGrand->_pLeft == pParent)
{
pGrand->_pLeft = pSonLeft;
}
else
{
pGrand->_pRight = pSonLeft;
}
}
//pSonLeft->_bf = 0;
//pParent->_bf = 0;
//如果旋转节点为根节点还要对根节点进行更新
if (pParent == _pRoot)
{
_pRoot = pSonLeft;
}
}
// 右左双旋
void RotateRL(Node* pParent)
{
RotateR(pParent->_pRight);
RotateL(pParent);
}
// 左右双旋
void RotateLR(Node* pParent)
{
RotateL(pParent->_pLeft);
RotateR(pParent);
}
// 为了操作树简单起见:获取根节点
Node*& GetRoot()
{
return _pRoot;
}
private:
//将树按中序显示的函数
void _showTree(Node* root)
{
if (root == nullptr)
{
return;
}
_showTree(root->_pLeft);
cout << root->_data << " ";
_showTree(root->_pRight);
}
//对树进行删除的函数
void destoryTree(Node* root)
{
if (root == nullptr)
{
return;
}
destoryTree(root->_pLeft);
destoryTree(root->_pRight);
delete root;
root = nullptr;
}
//Node* _pHead;
Node* _pRoot;
};
int main()
{
RBTree<int> t;
t.Insert(2);
t.Insert(5);
t.Insert(3);
t.Insert(4);
t.Insert(1);
t.Insert(8);
t.showTree();
printf("\n");
//RBTreeNode<int>* tn = t.Find(4);
//printf("%p",tn);
printf("最右侧节点值:%d\n",t.RightMost()->_data);
printf("最左侧节点值:%d\n",t.LeftMost()->_data);
if (t.IsValidRBTRee())
{
printf("恭喜,红黑树创建成功!\n");
}
return 0;
}