您的位置:首页 > 编程语言 > C语言/C++

红黑树

2016-09-12 20:31 267 查看

> 红黑树

红黑树(RB-Tree)是一种平衡二叉搜索树,虽然在本科的教材中对于红黑树讲解的内容很少,但是是一种被广泛应用的平衡二叉树,也是SGI STL唯一
实现的一种搜索树,作为关联式容器的底部机制之用。在C++ STL中,很多部分(包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中
的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。因此不言而喻其重要性了,但是也是最难啃的一块骨头之一。
红黑树不仅是一个二叉排序树,而且具有以下的性质:
1.每个节点不是红色就是黑色。
2.根节点为黑色。
3.如果一个节点的颜色为红色,则其子节点的颜色必须为黑色。
4.任何一个节点至NULL(树尾端)的任何路径,所含黑节点数必须相同。
5.为计算方便,我们一般视NULL为黑色节点。
由于红黑树以上的性质使一棵n个结点的红黑树始终保持了log2n的高度,从而也就说明了红黑树的查找、插入、删除的时间复杂度最坏为O(log2n)。
红黑树(RB-Tree)的节点设计:
红黑树有红黑两种颜色,并且拥有左右子节点,由于红黑树的各种操作需要方便的上溯到其父节点,因此增加一个指向其父节点的指针parent。


typedef struct _rb_tree_node_base
{
typedef bool color_type
color_type color;
_rb_tree_node_base* left;
_rb_tree_node_base* right;
_rb_tree_node_base* parent;
}node;
enum color{Black,Red};//插入一个节点,颜色初始化为红色


红黑树(RB-Tree)的插入:(该部分内容确认你已经了解了二叉排序树的插入以及树的旋转等内容)
红黑树中插入一个新的元素记为节点X,X的父节点记为P,X的父节点的父节点记为G,X的叔父节点记为U,后文中都是使用该符号,在图中显示如下图:




如果我们需要找到节点X的祖父节点G和叔父节点U,实现代码如下:


//查找祖父节点G
int grandparent(node x)
{
return x->parent->parent;
}
//查找叔父节点U
int uncle(node x)
{
if(x->parent==grandparent(x)->left)
{
return grandparent(x)->right;
}
else
{
return grandparent(x)->left;
}
}


红黑树插入新节点的情况分类:
S1.新插入节点X位于树根上,其父节点为NULL,则直接将给节点的颜色设置为Black,如图s1:




void Insert_S1(node x)
{
if(x->parent==NULL)
{
x->color=Black;
}
else  Insert_S2(x);
}


S2.新插入节点X的父节点为黑色节点,直接插入即可,如图s2:




void Insert_S2(node x)
{
if(x->parent->color==Black)
{
return ;
}
else Insert_S3(x);
}


S3.新插入节点X的父节点P以及叔父节点U都为红色,如图s3:(仅改变了颜色,其他情况不需要列出)




红黑树只要求红色节点的子节点必须为黑色,但是没有要求黑色节点的孩子也必须是红色,因此这种情况只需要改变其父节点和叔父节点的颜色为黑即可,不需要继续向上一层遍历,具体实现如下:

void Insert_S3(node x)
{
if(uncle(x)!=NULL && uncle(x)->color==Red)
{
x->parent->color=Black;
uncle(x)->color=Black;
}
else Insert_S4_1(x);
}


S4.新插入节点X的父节点为红色节点,叔父节点为黑色节点(NULL),如图s4:
由图可以知道在S4中还分为4中情况,其中2和3可以通过旋转变成1,4的情况,然后就可以统一处理。




2,3情况如下:2和3的情形可以通过一次旋转变成情形1和4,由于2,3是对称的,画图只画了情形2



void Insert_S4_1(node x)
{
if(x->parent==grandparent(x)->left && x==x->parent->right)
//对应情况2
{
RotateLeft(x->parent);
n=n->left;
Insert_S4_2(x);
}
else
if(x->parent==grandparent(x)->right && x==x->parent->left)
//对应情况3
{
RotateRight(x->parent);
n=n->right;
Insert_S4_2(x);
}
}


1,4情况如下:由于2,3是对称的,画图只画了情形2




void Insert_S4_2(node x)
{
if(x->parent==grandparent(x)->left && x==x->parent->left)
//对应情况1
{
RotateRight(grandparent(x));
x->parent->color=Black;
grandparent(x)->color=Red;
}
else
if(x->parent==grandparent(x)->right&&x==x->parent->right)
//对应情况4
{
RotateLeft(grandparent(x));
x->parent->color=Black;
grandparent(x)->color=Red;
}
}


1,4情况的代码还可以简化如下:


void Insert_S4_2(node x)
{
x->parent->color=Black;
grandparent(x)->color=Red;
if(x->parent==grandparent(x)->left && x==x->parent->left)
//对应情况1
{
RotateRight(grandparent(x));
}
else
if(x->parent==grandparent(x)->right&&x==x->parent->right)
//对应情况4
{
RotateLeft(grandparent(x));
}
}


本篇中还使用到的其他函数如下:


void RotateRight(node x)
{
temp=new node();
temp=x;
x=x->lchild;
x->rchild=temp;
temp->lchild=x->lchild->rchild;
}
void RotateLeft(node x)
{
temp=new node();
temp=x;
x=x->rchild;
x->lchild=temp;
temp->rchild=x->rchild->lchild;
}


本文是我自己学习了红黑树以后的一些见解,可能会有不对的地方,如果有请联系我,以便可以及时的更新,QQ179560574.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++语言