完整实现了一遍红黑树,程序就当作自己的笔记好了
红黑树,顾名思义,就是红黑相间的树,它借由红黑规则实现了二叉排序树的平衡。
红黑规则如下:
1.每个节点不是红就是黑
2.根总是黑色
3.若节点为红色,它的子节点必须为黑色
4.从根到叶的每条路径,必须包含相同数目的黑色节点
插入和删除节点时都要遵循红黑规则,具体表现如下:
1.首先所有新插入的节点都为红色
2.若新插入的节点的父节点为红色,则必须对红黑树进行调整
(1)旋转
单旋转:插入节点为外部子孙节点
双旋转:插入节点为内部子孙节点
(2)改变颜色
3.有两个红色子节点的节点也要进行处理
自己变红,儿子都变黑
上面只是对红黑树的一个简单概述,具体学习还要看算法书,下面是红黑树的代码实现。
对红黑树进行中序遍历即可得到递增的序列,故红黑树是有序的。
RB_Tree.h
#ifndef RB_TREE_H_
#define RB_TREE_H_
template<class Compareble>
class RedBlackTree;
template<class Compareble>
class RedBlackNode;
template<class Compareble>
class RedBlackTree
{
public:
RedBlackTree(const Compareble & negInf);
~RedBlackTree();
enum {RED,BLACK}; //利用枚举表示两种颜色
typedef RedBlackNode<Compareble> Node;
bool isEmpty() const;
void makeEmpty();
bool find(const Compareble & x) const;
void insert(const Compareble & x);
//private:
Node *header; //头节点
Node *nullNode; //空节点
Node *current;
Node *parent; //父节点
Node *grand; //祖父节点
Node *great; //曾祖父节点
void reclaimMemory(Node *t) const;
void rotateWithLeftChild(Node * &k2) const;
void rotateWithRightChild(Node * &k1) const;
void doubleRotateWithLeftChild(Node * &k3) const;
void doubleRotateWithRightChild(Node * &k1) const;
void handleReorient(const Compareble &item);
RedBlackNode<Compareble> * rotate(const Compareble & item, Node *theParent) const;
};
//红黑树节点
template<class Compareble>
class RedBlackNode
{
public:
Compareble element;
RedBlackNode *left;
RedBlackNode *right;
int color;
RedBlackNode(const Compareble & theElement = Compareble(),
RedBlackNode *lt = NULL,
RedBlackNode *rt = NULL,
int c = RedBlackTree<Compareble>::BLACK)
:element(theElement), left(lt), right(rt), color(c){}
friend class RedBlackTree<Compareble>; //将红黑树作为友元类用于操作私有对象
};
template<class Compareble>
RedBlackTree<Compareble>::RedBlackTree(const Compareble & negInf)
{
nullNode = new Node();
nullNode->left = nullNode->right = nullNode;
header = new Node(negInf);
header->left = header->right = nullNode; //左右孩子都指向空节点
}
template<class Compareble>
RedBlackTree<Compareble>::~RedBlackTree()
{
delete nullNode;
delete header;
}
//向红黑树中插入数据,在插入过程中需要实现自动平衡
template<class Compareble>
void RedBlackTree<Compareble>::insert(const Compareble & 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; //向下搜寻
//1.如果当前节点的左右儿子都是红色,需要进行处理
if (current->left->color == RED && current->right->color == RED)
handleReorient(x);
}
if (current != nullNode)
throw "element repeat!";
current = new Node(x, nullNode, nullNode);
if (x < parent->element)
parent->left = current;
else
parent->right = current;
//对于新插入节点也要进行处理
handleReorient(x);
}
//向右旋转
template<class Compareble>
void RedBlackTree<Compareble>::rotateWithLeftChild(Node * &k2) const
{
Node *k1 = k2->left;
//横向移动
k2->left = k1->right;
//上升和下降
k1->right = k2;
k2 = k1;
}
//向左旋转
template<class Compareble>
void RedBlackTree<Compareble>::rotateWithRightChild(Node * &k1) const
{
Node *k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1 = k2;
}
//向右双旋转
template<class Compareble>
void RedBlackTree<Compareble>::doubleRotateWithLeftChild(Node * &k3) const
{
rotateWithRightChild(k3->left);
rotateWithLeftChild(k3);
}
//向左双旋转
template<class Compareble>
void RedBlackTree<Compareble>::doubleRotateWithRightChild(Node * &k1) const
{
rotateWithLeftChild(k1->right);
rotateWithRightChild(k1);
}
//根据红黑规则调整红黑树
template<class Compareble>
void RedBlackTree<Compareble>::handleReorient(const Compareble &item)
{
//变色
//1.对于有两个红色子节点的节点进行变色处理
current->color = RED;
current->left->color = BLACK;
current->right->color = BLACK;
//2.当前节点的父节点为红色
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;
}
//根节点必须黑色
header->right->color = BLACK;
}
//根据内容自动判断旋转方向:
//左子树向右转->LL
//左子树向左转->LR
//右子树向右转->RL
//右子树向左转->RR
//参数1:当前节点数据,参数2:祖父节点(应比当前item大两辈)
template<class Compareble>
RedBlackNode<Compareble> * RedBlackTree<Compareble>::rotate(const Compareble & item, Node *theParent) const
{
if (item < theParent->element) //左子树
{
//如果item小于theParent->left->element,证明item是左子孙,要向右转
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;
}
}
//判断红黑树是否为空
template<class Compareble>
bool RedBlackTree<Compareble>::isEmpty() const
{
return header->right == nullNode;
}
//清空红黑树
template<class Compareble>
void RedBlackTree<Compareble>::makeEmpty()
{
reclaimMemory(header->right);
header->right = nullNode;
}
template<class Compareble>
void RedBlackTree<Compareble>::reclaimMemory(Node *t) const
{
//递归清除
//t等于t->left时证明到底了停止递归(都是nullNode)
if (t != t->left)
{
reclaimMemory(t->left);
reclaimMemory(t->right);
delete t;
}
}
//清空红黑树
template<class Compareble>
bool RedBlackTree<Compareble>::find(const Compareble & x) const
{
nullNode->element = x;
Node *curr = header->right;
while (1)
{
if (x < curr->element)
curr = curr->left;
else if (x>curr->element)
curr = curr->right;
else if (curr != nullNode)
return true;
else
return false;
}
}
#endif
RB_Tree.cpp
//红黑树实现
#include <iostream>
#include "RB_Tree.h"
using namespace std;
int main()
{
const int NEG_INF = -99999;
//使用一个很大的负数作为头指针的值
RedBlackTree<int> t(NEG_INF);
t.insert(50);
t.insert(40);
t.insert(30);
t.insert(20);
//如果不是红黑树,上面的输入会退化为链表,下面是验证过程
cout << "第一层:" << t.header->right->element << endl;
cout << "第二层:" << t.header->right->left->element << " " << t.header->right->right->element << endl;
cout << "第三层:" << t.header->right->left->left->element << endl;
//查找数据
cout << (t.find(20) ? "找到了" : "没找到") << endl;
//清空数据
cout << t.isEmpty() << endl;
t.makeEmpty();
cout << t.isEmpty() << endl;
system("pause");
return 0;
}