1.红黑树的概念
红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
2.红黑树的性质
1. 每个结点不是红色就是黑色。
2. 根节点是黑色的 。
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的。
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点 。
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)。
3.红黑树节点的定义
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _value;
Colour _col;
RBTreeNode(const T&value=T(),Colour col=RED)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _value(value)
, _col(col)
{}
};
4.红黑树的结构
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了 与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft 域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点,如下:
5.红黑树的插入
bool Insert(const T& data)
{
Node*& root = GetRoot();
if (root == nullptr)
{
root = new Node(data);
root->_col = BLACK;
root->_parent = _pHead;
_pHead->_left = LeftMost();
_pHead->_right = RightMost();
return true;
}
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
if (data > cur->_value)
{
parent = cur;
cur = cur->_right;
}
else if(data<cur->_value)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(data);
if (data > parent->_value)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
while (parent!=_pHead&&parent->_col==RED)
{
Node* grandparent = parent->_parent;
if (parent == grandparent->_left)
{
Node* uncle = grandparent->_right;
//情况一
if (uncle && uncle->_col == RED)//uncle存在且为红
{
uncle->_col = parent->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else//uncle不存在
{
//情况三后转为情况二
if (cur == parent->_right)
{
RotateL(parent);
swap(parent, cur);
}
//情况二
RotateR(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
}
else if (parent == grandparent->_right)
{
Node* uncle = grandparent->_left;
//情况一
if (uncle && uncle->_col == RED)//uncle存在且为红
{
uncle->_col = parent->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else//uncle不存在
{
//情况三后转为情况二
if (cur == parent->_left)
{
RotateR(parent);
swap(parent, cur);
}
//情况二
RotateL(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
}
}
root->_col = BLACK;
_pHead->_left = LeftMost();
_pHead->_right = RightMost();
return true;
}
// 右单旋
void RotateR(Node* pParent)
{
Node* root = GetRoot();
Node* subL = pParent->_left;
Node* subLR = subL->_right;
Node* grandparent = pParent->_parent;
pParent->_left = subLR;
if (subLR)
{
subLR->_parent = pParent;
}
subL->_right = pParent;
pParent->_parent = subL;
if (root == pParent)
{
root = subL;
subL->_parent = _pHead;
_pHead->_parent = root;
}
else
{
if (pParent == grandparent->_left)
{
grandparent->_left = subL;
}
else
{
grandparent->_right = subL;
}
subL->_parent = grandparent;
}
}
// 左单旋
void RotateL(Node* pParent)
{
Node* root = GetRoot();
Node* subR = pParent->_right;
Node* subRL = subR->_left;
Node* grandparent = pParent->_parent;
pParent->_right = subRL;
if (subRL)
{
subRL->_parent = pParent;
}
subR->_left = pParent;
pParent->_parent = subR;
if (root == pParent)
{
root = subR;
subR->_parent = _pHead;
_pHead->_parent = root;
}
else
{
if (pParent == grandparent->_left)
{
grandparent->_left = subR;
}
else
{
grandparent->_right = subR;
}
subR->_parent = grandparent;
}
}
// 获取红黑树最左侧节点
Node* LeftMost()
{
Node* cur = GetRoot();
if (!cur) return _pHead;
Node* parent = nullptr;
while (cur)
{
parent = cur;
cur = cur->_left;
}
return parent;
}
// 获取红黑树最右侧节点
Node* RightMost()
{
Node* cur = GetRoot();
if (!cur) return _pHead;
Node* parent = nullptr;
while (cur)
{
parent = cur;
cur = cur->_right;
}
return parent;
}
6.红黑树的验证
红黑树的检测分为两步:
1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)。
2. 检测其是否满足红黑树的性质。
void InOrder()
{
_InOrder(GetRoot());
cout << endl;
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_value << " ";
_InOrder(root->_right);
}
// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
bool IsValidRBTRee()
{
Node* root = GetRoot();
if (root == nullptr)
{
return true;
}
if (root->_col != BLACK)
{
cout << "违反性质二:根节点是黑色" << endl;
}
//一条路径的黑色节点个数
size_t pathBlack = 0;
Node* cur = root;
while (cur)
{
if (cur->_col == BLACK)
{
pathBlack++;
}
cur = cur->_left;
}
size_t blackCount = 0;
return _IsValidRBTRee(GetRoot(), blackCount, pathBlack);
}
private:
//根节点,黑色节点个数,路径中黑色节点个数
bool _IsValidRBTRee(Node* pRoot, size_t blackCount,const size_t pathBlack)
{
if (pRoot == nullptr)
{
if (blackCount != pathBlack)
{
cout << "pathBlack:" << pathBlack << endl;
cout << "blackCount:" << blackCount << endl;
cout << "违反性质四:每条路径都包含相同的黑色节点" << endl;
return false;
}
return true;
}
if (pRoot->_col == BLACK)
blackCount++;
Node* parent = pRoot->_parent;
if (pRoot->_col == RED)
{
if (parent&&parent->_col==RED)
{
cout << "违反性质三:不能有连续的红色节点" << endl;
return false;
}
}
return _IsValidRBTRee(pRoot->_left, blackCount, pathBlack) &&
_IsValidRBTRee(pRoot->_right, blackCount, pathBlack);
}
// 为了操作树简单起见:获取根节点
Node*& GetRoot()
{
return _pHead->_parent;
}
完整代码如下:
#pragma once
#include<iostream>
using namespace std;
enum Colour
{
RED,
BLACK
};
template<class T>
struct RBTreeNode
{
RBTreeNode<T>* _left;
RBTreeNode<T>* _right;
RBTreeNode<T>* _parent;
T _value;
Colour _col;
RBTreeNode(const T&value=T(),Colour col=RED)
:_left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _value(value)
, _col(col)
{}
};
// 请模拟实现红黑树的插入--注意:为了后序封装map和set,本文在实现时给红黑树多增加了一个头结点
template<class T>
class RBTree
{
typedef RBTreeNode<T> Node;
public:
RBTree()
{
_pHead = new Node;
_pHead->_left = _pHead;
_pHead->_right = _pHead;
}
// 在红黑树中插入值为data的节点,插入成功返回true,否则返回false
// 注意:为了简单起见,本次实现红黑树不存储重复性元素
bool Insert(const T& data)
{
Node*& root = GetRoot();
if (root == nullptr)
{
root = new Node(data);
root->_col = BLACK;
root->_parent = _pHead;
_pHead->_left = LeftMost();
_pHead->_right = RightMost();
return true;
}
Node* cur = root;
Node* parent = nullptr;
while (cur)
{
if (data > cur->_value)
{
parent = cur;
cur = cur->_right;
}
else if(data<cur->_value)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(data);
if (data > parent->_value)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
while (parent!=_pHead&&parent->_col==RED)
{
Node* grandparent = parent->_parent;
if (parent == grandparent->_left)
{
Node* uncle = grandparent->_right;
//情况一
if (uncle && uncle->_col == RED)//uncle存在且为红
{
uncle->_col = parent->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else//uncle不存在
{
//情况三后转为情况二
if (cur == parent->_right)
{
RotateL(parent);
swap(parent, cur);
}
//情况二
RotateR(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
}
else if (parent == grandparent->_right)
{
Node* uncle = grandparent->_left;
//情况一
if (uncle && uncle->_col == RED)//uncle存在且为红
{
uncle->_col = parent->_col = BLACK;
grandparent->_col = RED;
cur = grandparent;
parent = cur->_parent;
}
else//uncle不存在
{
//情况三后转为情况二
if (cur == parent->_left)
{
RotateR(parent);
swap(parent, cur);
}
//情况二
RotateL(grandparent);
parent->_col = BLACK;
grandparent->_col = RED;
}
}
}
root->_col = BLACK;
_pHead->_left = LeftMost();
_pHead->_right = RightMost();
return true;
}
// 右单旋
void RotateR(Node* pParent)
{
Node* root = GetRoot();
Node* subL = pParent->_left;
Node* subLR = subL->_right;
Node* grandparent = pParent->_parent;
pParent->_left = subLR;
if (subLR)
{
subLR->_parent = pParent;
}
subL->_right = pParent;
pParent->_parent = subL;
if (root == pParent)
{
root = subL;
subL->_parent = _pHead;
_pHead->_parent = root;
}
else
{
if (pParent == grandparent->_left)
{
grandparent->_left = subL;
}
else
{
grandparent->_right = subL;
}
subL->_parent = grandparent;
}
}
// 左单旋
void RotateL(Node* pParent)
{
Node* root = GetRoot();
Node* subR = pParent->_right;
Node* subRL = subR->_left;
Node* grandparent = pParent->_parent;
pParent->_right = subRL;
if (subRL)
{
subRL->_parent = pParent;
}
subR->_left = pParent;
pParent->_parent = subR;
if (root == pParent)
{
root = subR;
subR->_parent = _pHead;
_pHead->_parent = root;
}
else
{
if (pParent == grandparent->_left)
{
grandparent->_left = subR;
}
else
{
grandparent->_right = subR;
}
subR->_parent = grandparent;
}
}
// 检测红黑树中是否存在值为data的节点,存在返回该节点的地址,否则返回nullptr
Node* Find(const T& data)
{
if (GetRoot() == nullptr) return nullptr;
Node* cur = GetRoot();
while (cur)
{
if (cur->_value > data)
{
cur = cur->_left;
}
else if (cur->_value < data)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return nullptr;
}
void InOrder()
{
_InOrder(GetRoot());
cout << endl;
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_value << " ";
_InOrder(root->_right);
}
// 获取红黑树最左侧节点
Node* LeftMost()
{
Node* cur = GetRoot();
if (!cur) return _pHead;
Node* parent = nullptr;
while (cur)
{
parent = cur;
cur = cur->_left;
}
return parent;
}
// 获取红黑树最右侧节点
Node* RightMost()
{
Node* cur = GetRoot();
if (!cur) return _pHead;
Node* parent = nullptr;
while (cur)
{
parent = cur;
cur = cur->_right;
}
return parent;
}
// 检测红黑树是否为有效的红黑树,注意:其内部主要依靠_IsValidRBTRee函数检测
bool IsValidRBTRee()
{
Node* root = GetRoot();
if (root == nullptr)
{
return true;
}
if (root->_col != BLACK)
{
cout << "违反性质二:根节点是黑色" << endl;
}
//一条路径的黑色节点个数
size_t pathBlack = 0;
Node* cur = root;
while (cur)
{
if (cur->_col == BLACK)
{
pathBlack++;
}
cur = cur->_left;
}
size_t blackCount = 0;
return _IsValidRBTRee(GetRoot(), blackCount, pathBlack);
}
private:
//根节点,黑色节点个数,路径中黑色节点个数
bool _IsValidRBTRee(Node* pRoot, size_t blackCount,const size_t pathBlack)
{
if (pRoot == nullptr)
{
if (blackCount != pathBlack)
{
cout << "pathBlack:" << pathBlack << endl;
cout << "blackCount:" << blackCount << endl;
cout << "违反性质四:每条路径都包含相同的黑色节点" << endl;
return false;
}
return true;
}
if (pRoot->_col == BLACK)
blackCount++;
Node* parent = pRoot->_parent;
if (pRoot->_col == RED)
{
if (parent&&parent->_col==RED)
{
cout << "违反性质三:不能有连续的红色节点" << endl;
return false;
}
}
return _IsValidRBTRee(pRoot->_left, blackCount, pathBlack) &&
_IsValidRBTRee(pRoot->_right, blackCount, pathBlack);
}
// 为了操作树简单起见:获取根节点
Node*& GetRoot()
{
return _pHead->_parent;
}
private:
//_pHead与root互为parent节点,并且_pHead左右指向最左右两端的节点
Node* _pHead;
};