红黑树插入操作的C++实现

红黑树是具有如下顺序属性的二叉查找树
1、每个节点要么是红色,要么是黑色
2、根是黑色
3、所有叶子节点都是黑色(叶子是NIL节点)
4、每个红色节点的两个孩子节点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5、从根节点到NIL指针的每条路径必须包含相同数目的黑色节点

对NIL节点的理解是它不包含数据只充当树在此结束的指示

红黑树的插入的时候,把新插入的节点设置成红色,这样不会造成某一个分子的黑色节点数目超过其它分支的数目。但这样可能会违背性质4的要求,之所以选择违背性质4,是因为如果某一个分支多了一个黑色的节点很难进行调整。但如果只是颜色不符合规定,则相对容易调整。

删除操作太过复杂,未做实现。以后待定

用父代表当前插入节点的父节点,用祖父代表当前插入节点的父节点的父节点
调整的规则如下
1、父为黑,不需做额外的调整,设置好父子关系即可
2、父为红。父为红时,必定有祖父节点,用叔父代表其父节点的兄弟节点。
根据叔父节点颜色的不同,分两种情况讨论
2.1 叔父为红。(将其父和叔父变黑,将其祖父变红,然后递归向上检查。)
2.2 叔父为黑。根据子在父的方向与父在祖父方向的不同,又分两种情况
2.2.1 子在父与父在祖父的左右方向不同。
通过对子和父进行旋转,使得变成情况2.2.2
(子在父右则左旋,子在父左则右旋)
2.2.2 子在父与父在祖父的左右方向相同。
左旋或者右旋,使得父变成祖父和当前插入节点的父节点
然后将父节点变黑,祖父节点变红即可
(都在左,则右旋;都在右,则左旋)

下面是实现代码

/*
红黑树是具有如下顺序属性的二叉查找树
1、每个节点要么是红色,要么是黑色
2、根是黑色
3、所有叶子节点都是黑色(叶子是NIL节点)
4、每个红色节点的两个孩子节点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色节点)
4、从根节点到NIL指针的每条路径必须包含相同数目的黑色节点


对NIL节点的理解是它不包含数据只充当树在此结束的指示
*/
#include<iostream>
using std::ostream;
enum Color{red,black};
class TreeNode
{
private:
int value;
Color color;
TreeNode* lchild;
TreeNode* rchild;
TreeNode* parent;
/*构造一个专门的叶子节点*/
static TreeNode* NIL;
public:
TreeNode();
Color getColor()const;
TreeNode* getLeftChild()const;
TreeNode* getRightChild()const;
TreeNode* getParent() const;
int getValue() const;


private:
/*辅助函数,用来计算从当前节点开始,直到根节点总共有多少个黑色节点*/
int get_black_num();
friend class Tree;
friend ostream& operator<<(ostream&,const Tree&);
};
class Tree
{
private:
TreeNode* root;
public:
TreeNode* getRoot() const;
Tree();
void insert(int);
/*连续插入*/
void insert(int[] ,int);
void remove(int);
/*检查树的性质是否符合要求*/
bool check_tree();
/*给出要查询的值。找到返回0,否则返回-1*/
//int find(int);
private:
//插入过程中的一些辅助函数
/*对数进行调整*/
void updateTree(TreeNode*);
/*左旋*/
void leftRotate(TreeNode*);
/*右旋*/
void rightRotate(TreeNode*);
friend ostream& operator<<(ostream&,const Tree&);
};
/*打印红黑树用*/
ostream& operator<<(ostream& os,const Tree& tree);

#include"red_black_tree.h"
#include<vector>
using std::vector;
using std::cout;
using std::endl;
/*
TreeNode类的相关定义
*/
TreeNode* TreeNode::NIL=NULL;
TreeNode::TreeNode()
{
lchild=rchild=parent=NULL;
color=black;
}
int TreeNode::get_black_num()
{
int num=0;
TreeNode* p=this;
while(p)
{
if(p->color==black)
num++;
p=p->parent;
}
return num;
}
Color TreeNode::getColor() const
{
return color;
}
TreeNode* TreeNode::getLeftChild() const
{
return lchild;
}
TreeNode* TreeNode::getRightChild() const
{
return rchild;
}
TreeNode* TreeNode::getParent() const
{
return parent;
}
int TreeNode::getValue() const
{
return value;
}
/*
Tree类的函数定义
*/
Tree::Tree()
{
root=NULL;
if(!TreeNode::NIL)
{
TreeNode::NIL=new TreeNode;
TreeNode::NIL->color=black;
TreeNode::NIL->parent=NULL;
TreeNode::NIL->lchild=NULL;
TreeNode::NIL->rchild=NULL;
}
}
TreeNode* Tree::getRoot() const
{
return root;
}
void Tree::insert(int array[] ,int num)
{
for(int i=0;i<num;i++)
{
/*
cout<<"before insert "<<array[i]<<endl;
cout<<*this<<endl;
*/
insert(array[i]);
/*
cout<<"after insert "<<array[i]<<endl;
cout<<"check tree "<<this->check_tree()<<endl;
if(!this->check_tree())
break;
cout<<*this<<endl;
cout<<"..........................."<<endl;
*/
}
}
void Tree::updateTree(TreeNode* node)
{
if(node==root)
node->color=black;
else
{
//父为黑,返回即可。父子关系的设置在insert里面已经完成。本身节点为黑也可以直接返回即可
if(node->parent->color==black||node->color==black)
return;
else //父为红,必有祖父节点
{
TreeNode* grand=node->parent->parent;
TreeNode* parent=node->parent;
TreeNode* uncle=grand->lchild==parent?grand->rchild:grand->lchild;
if(uncle->color==red)  //叔父节点也为红
{
uncle->color=black;
parent->color=black;
grand->color=red;
updateTree(grand);
}
else  //父为红,叔父为黑
{
enum Dir{left,right};
Dir pDir=(parent==grand->lchild)?left:right;
Dir dir=(node==parent->lchild)?left:right;
if(pDir==dir)  //子父同向
{
if(dir==left)
rightRotate(parent);
else
leftRotate(parent);
parent->color=black;
grand->color=red;
}
else  //子父不同向
{
if(dir==left)
rightRotate(node);
else
leftRotate(node);
/*左旋或者右旋之后,从其子节点开始调整*/
updateTree(node->lchild);
updateTree(node->rchild);
}
}
}
}
}
void Tree::insert(int data)
{
if(!root) //如果树为空,就新建根节点
{
root=new TreeNode;
root->parent=NULL;
root->lchild=TreeNode::NIL;
root->rchild=TreeNode::NIL;
root->value=data;
root->color=black;
}
else
{
TreeNode* p=root; //用p来指向待插入节点的父节点
TreeNode* temp=data>(p->value)?p->rchild:p->lchild;
while(temp!=TreeNode::NIL)
{
p=temp;
temp=data>(p->value)?p->rchild:p->lchild;
}
/*新建一个红节点作为p的子节点插入,然后对树进行调整*/
TreeNode* newNode=new TreeNode;
newNode->color=red;
newNode->parent=p;
newNode->value=data;
newNode->lchild=newNode->rchild=TreeNode::NIL;
if(data<p->value)
p->lchild=newNode;
else
p->rchild=newNode;
updateTree(newNode);
}
}
/*
左旋
左旋之后的效果便是使p的父节点成为p左孩子节点。
p的左孩子节点成为p的父节点的孩子节点
*/
void Tree::leftRotate(TreeNode* node)
{
TreeNode* cur_left=node->lchild;
TreeNode* parent=node->parent;
TreeNode* grand=parent->parent;
/*代表其父节点在祖父节点的方向 1代表左,2代表右*/
if(grand)
{
int i=grand->lchild==parent?1:2;
/*对grand来说,改变的是左孩子或右孩子*/
if(i==1)
grand->lchild=node;
else
grand->rchild=node;
}
else
root=node;
/*对noe来说改变的是它的左孩子,和父节点*/
node->lchild=parent;
node->parent=grand;
/*对parent来说,改变的是父节点,右孩子*/
parent->parent=node;
parent->rchild=cur_left;
/*对cur_left来说,改变的是它的父节点*/
cur_left->parent=parent;
}
void Tree::rightRotate(TreeNode* node)
{
TreeNode* cur_right=node->rchild;
TreeNode* parent=node->parent;
TreeNode* grand=parent->parent;
/*若grand为NULL,则说明parent是root*/
if(grand)
{
/*代表其父节点在祖父节点的方向 1代表左,2代表右*/
int i=0;
i=grand->lchild==parent?1:2;
/*grand改变左子树或者右子树*/
if(i==1)
grand->lchild=node;
else
grand->rchild=node;
}
else
root=node;
/*node节点改变右子树和父节点*/
node->rchild=parent;
node->parent=grand;
/*parent节点改变父节点和左子树*/
parent->parent=node;
parent->lchild=cur_right;
/*cur_right改变父节点*/
cur_right->parent=parent;
}
/**/
void Tree::remove(int data)
{

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/5ea6c911ff2c0c4ee791ae5e980ae5b8.html