红黑树的实现
学了一下算法导论上的红黑树,这个数据结构基于二叉搜索树,二叉搜索树有一个缺点:如果数据以递增的顺序插入,得到的树深度就是n,进行操作就很不方便。红黑树就是在此基础上完善,自己可以自平衡,使两边始终保持接近,这样时间复杂度就降到O(lgn)。这个数据结构的确很难,插入和删除这两种操作非常复杂,自己按照书上给的伪代码实现了一下,思路是基本理清了,这种太复杂的数据结构想完全记住是不太现实的,能够掌握要点,下次看的时候可以马上回忆起来就可以了。
头文件:
#ifndef _RED_BLACK_TREE_
#define _RED_BLACK_TREE_
#define RED 82
#define BLACK 66
typedef struct RBTreeNode
{
unsigned int color;
int key;
struct RBTreeNode *left;
struct RBTreeNode *right;
struct RBTreeNode *pre;
}Node,*RBTree;
typedef struct RBRoot
{
Node *root;
}RBRoot;
RBRoot *CreateTree();
void InsertTree(RBRoot *tree, int key);
void DeleteNode(RBRoot *tree, Node *z);
void PrintTree(RBRoot *tree);
#endif
函数声明文件:
#include<iostream>
#include<stdlib.h>
#include"rbtree.h"
static void LeftRotate(RBRoot *tree, Node *x);
static void RightRotate(RBRoot *tree, Node *y);
static void RBInsertFixUp(RBRoot *tree, Node *z);
static void PrintNode(Node *node,int key, int direction);
static void InsertNode(RBRoot *tree, Node *z);
static void RBTransplant(RBRoot *tree, Node *u, Node *v);
static void RBDeleteFixUp(RBRoot *tree, Node *x);
RBRoot *CreateTree()
{
RBRoot *tree = (RBRoot *)malloc(sizeof(RBRoot));
tree->root = NULL;
return tree;
}
static void LeftRotate(RBRoot *tree, Node *x)
{
Node *y = x->right;
x->right = y->left;
if (y->left != NULL)
y->left->pre = x;
y->pre = x->pre;
if (x->pre == NULL)
tree->root = y;
else if (x == x->pre->left)
x->pre->left = y;
else
x->pre->right = y;
y->left = x;
x->pre = y;
}
static void RightRotate(RBRoot *tree, Node *y)
{
Node *x = y->left;
y->left = x->right;
if (x->right != NULL)
x->right->pre = y;
x->pre = y->pre;
if (y->pre == NULL)
tree->root = x;
else if (y == y->pre->left)
y->pre->left = x;
else
y->pre->right = x;
y->pre = x;
x->right = y;
}
static void RBInsertFixUp(RBRoot *tree, Node *z)
{
while (z->pre!=NULL&&z->pre->pre!=NULL&&z->pre->color == RED)//自己和父亲都是红结点
{
if (z->pre == z->pre->pre->left)
{
Node *y = z->pre->pre->right;
if (y!=NULL&&y->color == RED)//叔也为红结点就把父亲和叔叔都变成红色,爷爷变成黑色,这样达到一个z变成爷爷上移的作用,且黑高不变
{
z->pre->color = BLACK;
y->color = BLACK;
z->pre->pre->color = RED;
z = z->pre->pre;
}
else if (z == z->pre->right)//叔为黑且自己为右子树就进行一次左旋转换为第三种情况(叔不存在也是黑)
{
z = z->pre;
LeftRotate(tree, z);
}
else//将父亲和爷爷的颜色交换并对爷爷进行一次右旋,这样转换为第一种情况
{
z->pre->color = BLACK;
z->pre->pre->color = RED;
RightRotate(tree, z->pre->pre);
}
}
else//父亲为右子树的情况只要把上面的情况中所以Right和Left互换就行
{
Node *y = z->pre->pre->left;
if (y!=NULL&&y->color == RED)
{
z->pre->color = BLACK;
y->color = BLACK;
z->pre->pre->color = RED;
z = z->pre->pre;
}
else if (z == z->pre->left)
{
z = z->pre;
RightRotate(tree, z);
}
else
{
z->pre->color = BLACK;
z->pre->pre->color = RED;
LeftRotate(tree, z->pre->pre);
}
}
}
tree->root->color = BLACK;//将根结点设为黑色
}
static void InsertNode(RBRoot *tree, Node *z)
{
Node *y = NULL;
Node *x = tree->root;
while (x != NULL)//寻找合适的位置
{
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->pre = y;
if (y == NULL)
tree->root = z;
else if (z->key < y->key)
y->left = z;
else
y->right = z;
z->left = NULL;
z->right = NULL;
z->color = RED;
RBInsertFixUp(tree, z);
}
static void PrintNode(Node *node,int key, int direction)
{
if (node != NULL)
{
if(direction==0)
printf("%2d(B) is root\n", node->key);
else
printf("%2d(%c) is %2d's %6s child\n", node->key, node->color, key, direction == 1 ? "right" : "left");
PrintNode(node->left, node->key, -1);
PrintNode(node->right, node->key, 1);
}
}
void PrintTree(RBRoot *tree)
{
if (tree!=NULL&&tree->root != NULL)
PrintNode(tree->root, tree->root->key, 0);
}
void InsertTree(RBRoot *tree, int key)
{
Node* temp=(Node*)malloc(sizeof(Node));
temp->key = key;
temp->left = NULL;
temp->right = NULL;
temp->color = BLACK;
InsertNode(tree, temp);
}
void RBTransplant(RBRoot *tree, Node *u, Node *v)//用v来取代u
{
if (u->pre == NULL)
tree->root = v;
else if (u == u->pre->left)
u->pre->left = v;
else
u->pre->right = v;
v->pre = u->pre;
}
void RBDeleteFixUp(RBRoot *tree, Node *x)
{
while (x != tree->root&&x->color == BLACK)
{
if (x == x->pre->left)
{
Node *w = x->pre->right;//x为y的右子树,w为x的兄弟
if (w->color == RED)//情况1:兄弟为红色,左旋一次转换为情况2
{
w->color == BLACK;
x->pre->color = RED;
LeftRotate(tree, x->pre);
w = x->pre->right;
}
else
{
if (w->left->color == BLACK&&w->right->color == BLACK)//情况2:兄弟的两个孩子都是黑色,将兄弟削去一层黑色,将x上移,转换为情况1234
{
w->color = RED;
x = x->pre;
}
else if (w->right->color == BLACK)//情况3:兄弟的左孩子红右孩子黑,右旋一次转换为情况4
{
w->left->color = BLACK;
w->color = RED;
RightRotate(tree, w);
w = x->pre->right;
}
else//情况4:兄弟的孩子都是红色,此时坐旋使原x的路径增加一个黑色,这种情况出现说明完成红黑平衡
{
w->color = x->pre->color;
x->pre->color = BLACK;
w->right->color = BLACK;
LeftRotate(tree, x->pre);
x = tree->root;
}
}
}
else
{
Node *w = x->pre->left;
if (w->color == RED)
{
w->color == BLACK;
x->pre->color = RED;
RightRotate(tree, x->pre);
w = x->pre->left;
}
else
{
if (w->left->color == BLACK&&w->right->color == BLACK)//情况2:兄弟的两个孩子都是黑色,将兄弟削去一层黑色,将x上移,转换为情况1234
{
w->color = RED;
x = x->pre;
}
else if (w->left->color == BLACK)//情况3:兄弟的左孩子红右孩子黑,右旋一次转换为情况4
{
w->right->color = BLACK;
w->color = RED;
LeftRotate(tree, w);
w = x->pre->left;
}
else//情况4:兄弟的孩子都是红色,此时坐旋使原x的路径增加一个黑色,这种情况出现说明完成红黑平衡
{
w->color = x->pre->color;
x->pre->color = BLACK;
w->left->color = BLACK;
RightRotate(tree, x->pre);
x = tree->root;
}
}
}
}
x->color = BLACK;
}
void DeleteNode(RBRoot *tree,Node *z)
{
Node *y,*x;
y = z;
unsigned int origin_color = y->color;
if (z->left == NULL)
{
x = z->right;
RBTransplant(tree, z, z->right);
}
else if (z->right == NULL)
{
x = z->left;
RBTransplant(tree, z, z->left);
}
else
{
Node *temp = z->right;
while (temp->left!= NULL)
temp = temp->left;
y = temp;
origin_color = y->color;
x = y->right;
if (y->pre == z)
x->pre = y;
else
{
RBTransplant(tree, y, y->right);
y->right = z->right;
y->right->pre = y;
}
RBTransplant(tree, z, y);
y->left = z->left;
y->left->pre = y;
y->color = z->color;
}
if (origin_color == BLACK)
RBDeleteFixUp(tree, x);
}
实现文件:
#include<stdio.h>
#include<stdlib.h>
#include"rbtree.h"
int main()
{
int test[] = { 10, 40,30,60,90,70,20,50,80};
RBRoot* tree = CreateTree();
for (int i = 0; i < sizeof(test)/sizeof(int); i++)
InsertTree(tree, test[i]);
PrintTree(tree);
DeleteNode(tree,tree->root);
PrintTree(tree);
return 0;
}