红黑树是具有下列着色性质的二叉查找树:
1、每一个节点红或者黑
2、根是黑色的
3、如果一个节点是红色的,那么它的子节点必须是黑色的
4、从一个节点到一个null指针的每一条路径必须包含相同数目的黑色节点
在执行插入操作时,如果父节点为黑节点则直接插入红节点。但如果父节点是红节点,如果插入黑节点则会违反法则4,黑色节点数目变多。如果插入红节点则会违反法则3,出现连续的红节点。因此采用旋转操作和改变节点的颜色(约定null节点为黑)。
父节点(P)为红节点,插入红节点(X),执行单旋转或者双旋转(假设父节点的兄弟节点S为黑节点),G是祖父节点。双圆圈代表红节点
旋转后根节点为黑,G节点为红。整体满足红黑树性质。如果S节点为红,则需要将根节点涂成红色,G节点变为黑色。因为从根节点到C只有一个黑节点。若此时祖父节点为红,则需要继续旋转。因此采用自顶向下的方式保证父节点为红时,S不是红色的。
如果一个节点的两个儿子都是红节点,则进行颜色翻转。若此节点为根节点,则立马将其颜色翻转为黑色。
如果X的父节点为红,则进行旋转。之前的自顶向下的操作保证了X父节点的兄弟节点不可能为红。
实现代码如下
头文件
template <typename Comparable>
class RedBlackTree
{
public:
//negInf表示无穷小,头节点的值,头节点的右链指向根节点
explicit RedBlackTree(const Comparable & negInf);
RedBlackTree(const RedBlackTree & rhs);
RedBlackTree(RedBlackTree && rhs);
~RedBlackTree();
const Comparable & findMin()const;
const Comparable & findMax()const;
bool contains(const Comparable & x)const;
bool isEmpty()const;
void printTree()const;
void makeEmpty();
void insert(const Comparable & x);
void remove(const Comparable & x);
enum {RED,BLACK};
RedBlackTree & operator=(const RedBlackTree & rhs);
RedBlackTree & operator=(RedBlackTree && rhs);
private:
struct RedBlackNode
{
Comparable element;
RedBlackNode *left;
RedBlackNode *right;
int color;
RedBlackNode(const Comparable & theElement=Comparable{},
RedBlackNode *lt=nullptr,RedBlackNode *rt=nullptr,
int c=BLACK)
:element(theElement),left(lt),right(rt),color(c){}
RedBlackNode(Comparable && theElement=Comparable{},
RedBlackNode *lt=nullptr,RedBlackNode *rt=nullptr,
int c=BLACK)
:element(theElement),left(lt),right(rt),color(c){}
};
RedBlackNode *header;//头节点,指向根节点
RedBlackNode *nullNode;//空节点,为黑,指示nullptr指针
//用于insert操作及其辅助对象
RedBlackNode *current;
RedBlackNode *parent;
RedBlackNode *grand;
RedBlackNode *great;
void reclaimMemory(RedBlackNode *t);
void printTree(RedBlackNode *t)const;
RedBlackNode * clone(RedBlackNode * t)const;
//红黑树操作
void handleReorient(const Comparable & item);
RedBlackNode * rotate(const Comparable & item,RedBlackNode *theParent);
void rotateWithLeftChild(RedBlackNode * & k2);
void rotateWithRightChild(RedBlackNode * & k1);
};
cpp文件
#include "RedBlackTree.hpp"
#include <iostream>
using namespace std;
template <typename Comparable>
RedBlackTree<Comparable>::RedBlackTree(const Comparable & negInf)
{
nullNode=new RedBlackNode;
nullNode->left=nullNode->right=nullNode;
header=new RedBlackNode{negInf};
header->left=header->right=nullNode;
}
template <typename Comparable>
void RedBlackTree<Comparable>::printTree()const
{
if(header->right==nullNode)
cout<<"Empty Tree"<<endl;
else
printTree(header->right);
}
template <typename Comparable>
void RedBlackTree<Comparable>::printTree(RedBlackNode *t)const
{
if(t!=nullNode)
{
printTree(t->left);
cout<<t->element;
printTree(t->right);
}
}
template <typename Comparable>
RedBlackTree<Comparable>::RedBlackTree(const RedBlackTree & rhs)
{
nullNode=new RedBlackNode;
nullNode->left=nullNode->right=nullNode;
header=new RedBlackNode{rhs.header->element};
header->left=nullNode;
header->right=clone(rhs.header->right);
}
template <typename Comparable>
typename RedBlackTree<Comparable>::RedBlackNode *
RedBlackTree<Comparable>::clone(RedBlackNode * t)const
{
if(t==t->left)//不能使用t==nullNode,因为是两个不同的对象
return nullNode;
else
return new RedBlackNode{t->element,clone(t->left),clone(t->right),t->color};
}
//传入根节点的父节点,返回根节点(根节点指的是子树的根节点,不是整棵树的根节点)
template <typename Comparable>
typename RedBlackTree<Comparable>::RedBlackNode *
RedBlackTree<Comparable>::rotate(const Comparable & item,RedBlackNode * theParent)
{
if(item<theParent->element)
{
item<theParent->left->element?
rotateWithLeftChild(theParent->left):
rotateWithRightChild(theParent->left);
return theParent->left;
}
else
{
item<theParent->right->element?
rotateWithLeftChild(theParent->right):
rotateWithRightChild(theParent->right);
return theParent->right;
}
}
//如果存在一个节点有两个红儿子,则执行颜色翻转和旋转,item是要被插入的项
template <typename Comparable>
void RedBlackTree<Comparable>::handleReorient(const Comparable & item)
{
current->color=RED;
current->left->color=BLACK;
current->right->color=BLACK;
if(parent->color==RED)
{
grand->color=RED;
//判断是否是双旋转
if(item<grand->element!=item<parent->element)
parent=rotate(item,grand);
current=rotate(item, great);
current->color=BLACK;//current此时为子树根节点,旋转后子树根节点始终为黑
}
header->right->color=BLACK;//根节点始终为黑
}
template <typename Comparable>
void RedBlackTree<Comparable>::insert(const Comparable & x)
{
current=parent=grand=header;
nullNode->element=x;
while (current->element!=x)
{
great=grand;grand=parent;parent=current;
current=x<current->element?current->left:current->right;
if(current->left->color==RED&¤t->right->color==RED)
{
handleReorient(x);
}
}
if(current!=nullNode)//已经存在x
return;
//插入树叶
current=new RedBlackNode{x,nullNode,nullNode};
if(x<parent->element)
parent->left=current;
else
parent->right=current;
handleReorient(x);
}
//单旋转,见AVL树操作
template <typename Comparable>
void RedBlackTree<Comparable>::rotateWithLeftChild(RedBlackNode * & k2)
{
RedBlackNode * k1=k2->left;
k2->left=k1->right;
k1->right=k2;
k2=k1;
}
template <typename Comparable>
void RedBlackTree<Comparable>::rotateWithRightChild(RedBlackNode * & k1)
{
RedBlackNode * k2=k1->right;
k1->right=k2->left;
k2->left=k1;
k1=k2;
}