红黑树是一种平衡的二叉排序树,首先它是二叉排序树,即它的节点之间都是有序的; 其次,它是一种平衡树,因此它的查找效率是比较优的
红黑树的五个性质:
1、每个节点要么是红色的要么是黑色的
2、根节点必须是黑色的
3、叶子节点(即NULL节点)是黑色的
4、如果一个节点是红色的,那么它的两个孩子必须是黑色的
5、对于每一个节点,它到叶子节点的所有路径包含的黑色节点的个数都相同
由于性质5的原因,新插入的节点的颜色必须是红色的!
由于性质4的原因,新插入节点可能破坏了红黑树的平衡,因此需要调整
注意每一个节点的初始插入位置都是在树的最底层,插入之后判断是否违反了红黑树的性质,如果违反了,那么需要进行调整
实现:
#ifndef RB_RBTree_H
#define RB_RBTree_H
#include <iostream>
#include <string>
using namespace std;
struct RBTreeNode;
// 树节点数据的比较函数,如果不设置那么就默认按照指针进行比较
typedef int (*RBTreeDataCompareFunc)(void* data1,void* data2);
// 遍历一棵树的处理函数
typedef void (*RBTreeNodeHandle)(void* userData,RBTreeNode* node);
// 红黑树的节点
struct RBTreeNode
{
enum RBTreeNodeColor
{
// 红色
red,
// 黑色
black,
};
RBTreeNode()
{
data = 0;
left = 0;
right = 0;
parent = 0;
color = red;
}
// 数据
void* data;
// 颜色
int color;
// 父亲
struct RBTreeNode* parent;
// 左孩子
struct RBTreeNode* left;
// 右孩子
struct RBTreeNode* right;
// 取得以node为根的子树的最小节点
static RBTreeNode* Mini(RBTreeNode* node)
{
if(node == 0)
return 0;
while(node->left != 0)
node =node->left;
return node;
}
// 取得以node为子树的最大节点
static RBTreeNode* Max(RBTreeNode* node)
{
if(node == 0)
return 0;
while(node->right != 0)
node = node->right;
return node;
}
};
typedef RBTreeNode* PRBTreeNode;
// 红黑树
class RBTree
{
public:
RBTree();
RBTree(RBTreeDataCompareFunc compareFunc);
~RBTree();
RBTreeNode* Root();
size_t Size();
bool Empty();
void Clear();
// 插入节点
RBTreeNode* Insert(void* data);
// 获得最左边的节点
RBTreeNode* LeftMost();
// 获得最右边的节点
RBTreeNode* RightMost();
// 重新调整平衡
void ReBalance(RBTreeNode* x);
// 向左旋转
void RotateLeft(RBTreeNode* x);
// 向右旋转
void RotateRight(RBTreeNode* x);
// 删除值等于data的节点
void Remove(void* data);
// 删除node节点,连同它的子节点
void Remove(RBTreeNode* node);
// 删除node节点的左节点(连同它的子节点)
void RemoveLeft(RBTreeNode* node);
// 删除node节点的右节点(连同它的子节点)
void RemoveRight(RBTreeNode* node);
// 中序递归遍历
void MidOrderTraverse(RBTreeNodeHandle handle,void* userData,RBTreeNode* node = 0);
// 前序递归遍历
void PreOrderTraverse(RBTreeNodeHandle handle,void* userData,RBTreeNode* node = 0);
// 后续递归遍历
void PostOrderTraverse(RBTreeNodeHandle handle,void* userData,RBTreeNode* node = 0);
// 查找
RBTreeNode* Find(void* data);
RBTreeNode* Find(void* data,PRBTreeNode& parentNode);
size_t Depth(RBTreeNode* node = 0);
size_t Leafs(RBTreeNode* node = 0);
private:
void ClearRecu(RBTreeNode* node);
RBTreeNode* FindRecu(RBTreeNode* node,void* data,PRBTreeNode& parentNode);
// 中序递归遍历
void MidOrderTraverseRecu(RBTreeNodeHandle handle,void* userData,RBTreeNode* node );
// 前序递归遍历
void PreOrderTraverseRecu(RBTreeNodeHandle handle,void* userData,RBTreeNode* node );
// 后续递归遍历
void PostOrderTraverseRecu(RBTreeNodeHandle handle,void* userData,RBTreeNode* node );
size_t DepthRecu(RBTreeNode* node );
size_t LeafsRecu(RBTreeNode* node );
private:
// m_pHead的父亲始终指向根节点
// m_pHead的left指向最左的节点(也就是值最小的节点)
// m_pHead的right指向最右的节点(也就是值最大的节点)
RBTreeNode* m_pHead;
// 红黑树中节点的个数
size_t m_nSize;
// 比较函数
RBTreeDataCompareFunc m_CompareFunc;
};
#endif // RBTree_H
#include "rbtree.h"
// 默认的节点值比较函数
int DefaultRBTreeNodeCompareFunc(void* data1,void* data2)
{
if(data1 == data2)
return 0;
if(data1 < data2)
return -1;
return 1;
}
// 构造函数
RBTree::RBTree()
{
m_pHead = new RBTreeNode;
m_pHead->color = RBTreeNode::red;
m_pHead->left = m_pHead;
m_pHead->right = m_pHead;
m_pHead->parent = 0;
m_nSize = 0;
m_CompareFunc = DefaultRBTreeNodeCompareFunc;
}
RBTree::RBTree(RBTreeDataCompareFunc compareFunc)
{
m_nSize = 0;
m_pHead = new RBTreeNode;
m_pHead->color = RBTreeNode::red;
m_pHead->left = m_pHead;
m_pHead->right = m_pHead;
m_pHead->parent = 0;
m_CompareFunc = compareFunc;
}
RBTree::~RBTree()
{
Clear();
delete m_pHead;
}
// 返回根节点
RBTreeNode* RBTree::Root()
{
return m_pHead->parent;
}
// 返回红黑树最左边的节点,即最小值所在的节点
RBTreeNode* RBTree::LeftMost()
{
return m_pHead->left;
}
// 返回红黑树最优边的节点,即最大值所在的节点
RBTreeNode* RBTree::RightMost()
{
return m_pHead->right;
}
// 返回红黑树的节点个数
size_t RBTree::Size()
{
return m_nSize;
}
bool RBTree::Empty()
{
if(0 == m_nSize)
return true;
return false;
}
// 清理红黑树
void RBTree::Clear()
{
ClearRecu(m_pHead->parent);
m_pHead->color = RBTreeNode::red;
m_pHead->left = m_pHead;
m_pHead->right = m_pHead;
m_pHead->parent = 0;
m_nSize = 0;
}
// 递归清理
void RBTree::ClearRecu(RBTreeNode *node)
{
if(node == 0)
return ;
ClearRecu(node->left);
ClearRecu(node->right);
delete node;
--m_nSize;
}
// 节点node的值要大于等于左孩子的值
// 插入节点
RBTreeNode* RBTree::Insert(void* data)
{
// 创建一个新节点
RBTreeNode* insertNode = new RBTreeNode;
insertNode->data = data;
// 新插入节点的颜色是红色的
insertNode->color = RBTreeNode::red;
++m_nSize;
// 如果根节点为空,那么把当前节点设置为根节点
// 把颜色调整为黑,因为红黑树的根是黑色的
if(m_pHead->parent == 0)
{
m_pHead->parent = insertNode;
m_pHead->parent->color = RBTreeNode::black;
m_pHead->left = insertNode;
m_pHead->right = insertNode;
}
else
{
RBTreeNode* node = m_pHead->parent;
RBTreeNode* currentpNode = node;
// 找到新节点应该插入的位置
while(node != 0)
{
currentpNode = node;
int compareRet = m_CompareFunc(node->data,data);
if(compareRet < 0)
{
node = node->right;
}
else
// compareRet >= 0
{
node = node->left;
}
}
// 把新节点插入红黑树中
if(m_CompareFunc(currentpNode->data,data) < 0)
{
currentpNode->right = insertNode;
insertNode->parent = currentpNode;
if(RightMost() == currentpNode)
m_pHead->right = insertNode;
}
else
{
currentpNode->left = insertNode;
insertNode->parent = currentpNode;
if(LeftMost() == currentpNode)
m_pHead->left = insertNode;
}
}
// 插入好了
// 接下来需要进行调整
ReBalance(insertNode);
}
// 红黑树的特点:
// (1)根节点是黑色的
// (2)父子节点不能同时是红色(即如果父亲节点是红色,那么子节点必须是黑色)
// (3)任一节点到NULL(即树尾端)的任何路径包含的黑色节点个数都相同
// 假设插入节点是X,X的父亲节点是P,X的祖父是G,X的曾祖父是GG,X的伯父或者叔叔(即P的兄弟)是S
// 有四种情况:
// 1、如果P的颜色是黑色,插入之后可以直接返回
// 2、如果P的颜色是红色,那么进行如下处理
// 2.1、S是黑色:
// 2.1.1、LL:如果X是外侧插入,直接进行LL旋转(对P和G),改变P和G的颜色(P改成黑,G改成红色)
// 2.1.2、LR:如果X是内侧插入,进行LR旋转,先对P、X进行旋转,然后改变G和X的颜色(G改成红色,X改成黑色)
// 再对G进行旋转
// 2.2、S是红色:
// 2.2.1、LL:如果X是外侧插入,直接进行LL旋转(对P和G),改变X的颜色(变成黑色),如果GG是黑色,那么完成
// 否则还需要继续向上处理
//
/*
* 预处理过程:
* 从某个节点依次向上,如果遇到某个节点X的两个子节点的颜色都是红色
* 那么把X两个子节点的颜色改成黑色,X的颜色改成红色,然后继续向上
* 如果变换之后,X的父亲和X都是红色(那此时X的祖父必是黑色,因为X的父亲是红色),
* 如果此时X的兄弟是红色,那么可以继续向上处理(因为符合P的两个子节点都是红色这一条件)
* 如果此时X的兄弟是黑色(那么不满足继续向上的条件了),需要进行旋转
* 那么对X的父亲进行旋转即可,这里只需要一个LL(或RR)或LR(或RL)旋转即可,而不需要进行多次的向上遍历然后旋转
* 单旋转的时候需要改变P和G的颜色
* 双旋转的第一次旋转需要改变X和G的颜色,第二次旋转不需要改变颜色
*/
void RBTree::ReBalance(RBTreeNode *x)
{
// 插入节点的起始颜色都是红色
x->color = RBTreeNode::red;
// 如果P的颜色是黑色,对应情况1,不会进入循环
// 一直从x向上遍历,直到到达根节点
while(x != m_pHead->parent && x->parent->color == RBTreeNode::red)
{
// P的颜色是红色!!!
// 如果P是G的左孩子
if(x->parent == x->parent->parent->left)
{
// 取得S
RBTreeNode* uncle = x->parent->parent->right;
// S的颜色是红色
if(uncle && uncle->color == RBTreeNode::red)
{
// 这是预处理过程
// P的颜色设置为黑色
x->parent->color = RBTreeNode::black;
// S的颜色设置为黑色
uncle->color = RBTreeNode::black;
// G的颜色设置为红色
x->parent->parent->color = RBTreeNode::red;
// 然后把X向上移动到G,继续向上遍历,这是一个自下而上的预处理过程
x = x->parent->parent;
}
else
// S的颜色是黑色
{
// 如果X是P的右孩子,而P是G的左孩子,那么将进行LR旋转
// LR选择即先左旋转,再右旋转
if(x == x->parent->right)
{
x = x->parent;
RotateLeft(x);
}
// 如果X是P的左孩子,而P是G的左孩子,那么将进行LL旋转(直接右旋转即可)
// P的颜色变为黑色
x->parent->color = RBTreeNode::black;
// G的颜色变为红色
x->parent->parent->color = RBTreeNode::red;
// 进行旋转
RotateRight(x->parent->parent);
}
}
else
// 如果P是G的右孩子
{
RBTreeNode* uncle = x->parent->parent->left;
// S的颜色是红色
if(uncle && uncle->color == RBTreeNode::red)
{
// 这是预处理过程
// P的颜色设置为黑色
x->parent->color = RBTreeNode::black;
// S的颜色设置为黑色
uncle->color = RBTreeNode::black;
// G的颜色设置为红色
x->parent->parent->color = RBTreeNode::red;
// 把X移动到G,依次向上处理,这是一个子下而上的预处理过程
x = x->parent->parent;
}
else
// S的颜色是黑色
{
// 如果X是P的左孩子,而P是G的右孩子,那么需要进行RL旋转(先右旋转,再左旋转)
if(x == x->parent->left)
{
x =x->parent;
RotateRight(x);
}
// 如果X是P的右孩子,那么直接进行RR旋转即可(即进行左旋转)
// P的颜色改成黑色
x->parent->color = RBTreeNode::black;
// G的颜色改成红色
x->parent->parent->color = RBTreeNode::red;
// 旋转
RotateLeft(x->parent->parent);
}
}
}
m_pHead->parent->color = RBTreeNode::black;
}
// 左旋转(以X为中间进行逆时针旋转)
// 旋转之后,X的右孩子right取代X的位置,而X则成为right的左孩子
// 因此right的左孩子应该成为X的右孩子
void RBTree::RotateLeft(RBTreeNode *x)
{
// 取得x的左孩子
RBTreeNode* right = x->right;
// x的右孩子应该是right的左孩子
x->right =right->left;
if(right->left != 0)
{
// right的左孩子的父亲是x
right->left->parent = x;
}
// right的父亲是x原来的父亲
right->parent = x->parent;
if(x == m_pHead->parent)
{
m_pHead->parent = right;
}
else if(x == x->parent->left)
{
x->parent->left = right;
}
else
{
x->parent->right = right;
}
// x变成right的左孩子
right->left = x;
x->parent = right;
}
// 右旋转(以X为中心,按照顺时针进行旋转)
// 旋转之后X的左孩子left取代X的位置,X成为left的右孩子
// left原来的右孩子变成X的左孩子
void RBTree::RotateRight(RBTreeNode *x)
{
RBTreeNode* left = x->left;
x->left =left->right;
if(left->right != 0)
{
left->right->parent = x;
}
left->parent = x->parent;
if(x == m_pHead->parent)
{
m_pHead->parent = left;
}
else if(x == x->parent->right)
{
x->parent->right = left;
}
else
{
x->parent->left = left;
}
left->right = x;
x->parent = left;
}
RBTreeNode* RBTree::Find(void *data)
{
PRBTreeNode node = 0;
return FindRecu(m_pHead->parent,data,node);
}
RBTreeNode* RBTree::Find(void *data, PRBTreeNode &parentNode)
{
parentNode = 0;
return FindRecu(m_pHead->parent,data,parentNode);
}
RBTreeNode* RBTree::FindRecu(RBTreeNode *node, void *data,PRBTreeNode& parentNode)
{
if(node == 0)
{
parentNode = 0;
return 0;
}
if(m_CompareFunc(node->data,data) == 0)
return node;
parentNode = node;
RBTreeNode* temp = FindRecu(node->left,data,parentNode);
if(0 != temp)
return temp;
parentNode = node;
return FindRecu(node->right,data,parentNode);
}
void RBTree::PreOrderTraverse(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
if(node == 0)
return PreOrderTraverseRecu(handle,userData,m_pHead->parent);
return PreOrderTraverseRecu(handle,userData,node);
}
void RBTree::MidOrderTraverse(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
if(node == 0)
return MidOrderTraverseRecu(handle,userData,m_pHead->parent);
return MidOrderTraverseRecu(handle,userData,node);
}
void RBTree::PostOrderTraverse(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
if(node == 0)
return PostOrderTraverseRecu(handle,userData,m_pHead->parent);
return PostOrderTraverseRecu(handle,userData,node);
}
void RBTree::PreOrderTraverseRecu(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
if(node == 0)
return ;
handle(userData,node);
PreOrderTraverseRecu(handle,userData,node->left);
PreOrderTraverseRecu(handle,userData,node->right);
}
void RBTree::MidOrderTraverseRecu(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
if(node == 0)
return ;
MidOrderTraverseRecu(handle,userData,node->left);
handle(userData,node);
MidOrderTraverseRecu(handle,userData,node->right);
}
void RBTree::PostOrderTraverseRecu(RBTreeNodeHandle handle, void *userData, RBTreeNode *node)
{
if(node == 0)
return ;
PostOrderTraverseRecu(handle,userData,node->left);
PostOrderTraverseRecu(handle,userData,node->right);
handle(userData,node);
}
size_t RBTree::Depth(RBTreeNode *node)
{
if(node == 0)
return DepthRecu(m_pHead->parent);
else
return DepthRecu(node);
}
size_t RBTree::DepthRecu(RBTreeNode *node)
{
if(node == 0)
return 0;
if(node->left == 0 && node->right == 0)
return 1;
int leftDepth = DepthRecu(node->left);
int rightDepth = DepthRecu(node->right);
if(leftDepth > rightDepth)
return leftDepth + 1;
else
return rightDepth + 1;
}
size_t RBTree::Leafs(RBTreeNode *node)
{
if(node == 0)
return LeafsRecu(m_pHead->parent);
else
return LeafsRecu(node);
}
size_t RBTree::LeafsRecu(RBTreeNode *node)
{
if(node == 0)
return 0;
if(node->left == 0 && node->right == 0)
return 1;
else
return LeafsRecu(node->left) + LeafsRecu(node->right);
}