您的位置:首页 > 其它

红黑树(red black tree)的实现

2009-12-02 20:39 567 查看
以前看过几次红黑树的介绍,但是一直感觉云里雾里的,不是很明白,什么LL旋转、RR旋转之类的,分类讨论也不是很清晰,前几天偶然网上碰到一本电子书:[麻省理工学院-算法导论].Introduction.to.Algorithms,看过后感觉豁然开朗,书中描述的比较清楚,看过后代码的实现很简单。

关于红黑树的介绍,cnblog的abatei老兄的文章写得比较详细,详情请点击这里

关于红黑树的查找就不用说了(就是二叉树的查找),这里主要说一下插入和删除。

红黑树其实就是特殊的二叉树,要满足一下五个条件:

1、 每个结点的颜色只能是红色或黑色。

2、 根结点是黑色的。

3、 每个叶子结点都带有两个空的黑色结点(被称为黑哨兵)

4、 如果一个结点是红的,则它的两个儿子都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。

5、 对于每个结点来说,从该结点到其子孙叶结点的所有路径上包含相同数目的黑结点。

插入:插入主要分为两个步骤,首先就是简单的二叉树的插入,然后就是红黑树的调整。

每次经过第一步骤插入新元素后,首先将此节点的颜色置为红色,然后调整红黑树,大体分为两种:当前插入的节点的父节点是其祖父节点的左节点或者右节点(其实说白了就是一种,因为左、右是对称的);而每种又有三种情形,下面只讨论当前插入的节点色父节点是左子节点的情况,因为右是对称的:

1. 当前节点的父节点的兄弟节点的颜色为红色:将当前节点的父节点和父节点的兄弟节点都置为黑色,并将祖父节点置为红色,然后将当前节点指向祖父节点,继续

2. 当前节点为其父节点的右子节点:当前节点指向其父节点,然后以当前节点为顶点进行左旋转

3. 当前节点为其父节点的左子节点:当前节点的父节点置为黑色,祖父节点置为红色,然后以祖父节点为顶点进行右旋转

每种情况的解决都要确保不影响当前节点的子树满足红黑树的5个性质。

删除:删除也是两个步骤,简单的二叉树的删除以及红黑树的调整,但是比插入复杂多了

只有在删除黑色节点的情况下才需要调整红黑树,而删除红色节点并不会破坏红黑树的结构

由于左右的对称性,这里只讨论左边的情况:

1. 当前节点的兄弟节点为红色节点

2. 当前节点的兄弟节点的子节点都为黑色

3. 当前节点的兄弟节点的右子节点为黑色

4. 当前节点的兄弟节点的左子节点为黑色

具体实现请参照下面的代码,我就不再赘述了^_^

具体代码如下:

rbtree.h

#ifndef NEWSENTRY_REDBLACK_TREE_H
#define NEWSENTRY_REDBLACK_TREE_H

/*
* A binary search tree is a red-black tree if it satisfies the following red-black properties:
* 1. Every node is either red or black.
* 2. The root is black.
* 3. Every leaf (NIL) is black.
* 4. If a node is red, then both its children are black.
* 5. For each node, all paths from the node to descendant leaves contain the same number of black nodes.
*
*/

/*
* self-defined typedefs
* You can change the typedefs to their own types
* but remember that this implementation of red black tree
* does not use deep copy, so if KeyType is something about
* string, you have to maintain the memory on your own!
*
* */
typedef const char * KeyType;
typedef int ValueType;
typedef void * rbt_handle_t;
typedef enum { false, true } bool;

/*
* Function pointer to compare keys
* return 0 if they are equal
* negative if the first one is less than the second
* positive otherwise
*
* */
typedef int (*pfn_cmp)(KeyType, KeyType);

typedef enum {
RBT_SUCCESS, 				/* suceessful */
RBT_RBTREE_IS_NULL, 		/* red black tree is NULL */
RBT_RBTREE_IS_EMPTY, 		/* red black tree is empty */
RBT_OUT_OF_MEMORY, 		/* alloc memory failed: out of memory */
RBT_KEY_EXISTED, 			/* the key has existed, only used in inserting */
RBT_KEY_NONE_EXISTED		/* the key doesnot exist, only meaningful in removing method */
} RbtStatus;

/*
* Create red black tree
* user can define their own cmp function
* but the function must be compatible with pfn_cmp
*
* */
rbt_handle_t create_red_black_tree(pfn_cmp cmp);
void release_red_black_tree(rbt_handle_t root);

/*
* Insert the key and value to red black tree
* Only RBT_SUCCESS (which is 0) implies success, others mean failure
* refer to above enum to know the detailed information about failure
*
* @tree:		handle to red black tree
* @key:		keyword on which sorting is based on
* @value:		real data stored
*
* */
RbtStatus rbt_insert(rbt_handle_t tree, KeyType key, ValueType value);
RbtStatus rbt_find(rbt_handle_t tree, KeyType key);

/*
* Remove the node with key as keyword from red black tree
* Only RBT_SUCCESS (which is 0) implies success, others mean failure
* refer to above enum type to know the detailed information about failure
*
* @tree:		handle to red black tree
* @key:		keyword
* @value:		store the keyword's corresponding value if succeeded, otherwise undefined
*
* */
RbtStatus rbt_remove(rbt_handle_t tree, KeyType key, ValueType * value);

/* Check whether the red black tree is valid
* i.e. make sure there is not violation of the 5 properties */
bool rbt_is_valid(rbt_handle_t tree);

#endif


rbtree.c

//#include <stdio.h>
#include <stdlib.h>
//#include <string.h>

#include "rbtree.h"

/*
* A binary search tree is a red-black tree if it satisfies the following red-black properties:
* 1. Every node is either red or black.
* 2. The root is black.
* 3. Every leaf (NIL) is black.
* 4. If a node is red, then both its children are black.
* 5. For each node, all paths from the node to descendant leaves contain the same number of black nodes.
*
*/

typedef enum { RED, BLACK } ColorType;

typedef struct rbt_node
{
struct rbt_node * father_;
struct rbt_node * left_;
struct rbt_node * right_;
ColorType color_;
KeyType key_;
ValueType value_;
} rbt_node_t;

typedef struct red_black_tree
{
rbt_node_t * root_;
pfn_cmp cmp_;
} red_black_tree_t;

/* Sentinel node, all leaves's children are set to Sentinel */
static rbt_node_t Sentinel = { NULL, &Sentinel, &Sentinel, BLACK, (KeyType)0, (ValueType)0 };
static rbt_node_t * nil_ = &Sentinel;

int default_compare(KeyType a, KeyType b);

rbt_node_t * create_rbt_node(KeyType key, ValueType value);

/* auxiliary functions to manipulate red-black-tree */
rbt_node_t * auxiliary_rbt_find(rbt_node_t * root, KeyType key, pfn_cmp cmp);
rbt_node_t * auxiliary_rbt_insert(rbt_node_t * root, rbt_node_t * node, pfn_cmp cmp);
rbt_node_t * auxiliary_rbt_remove(rbt_node_t * tree, rbt_node_t * node, pfn_cmp cmp);
rbt_node_t * auxiliary_rbt_insert_fixup(rbt_node_t * root, rbt_node_t * node);
rbt_node_t* auxiliary_rbt_remove_fixup(rbt_node_t * root, rbt_node_t * node);
rbt_node_t * auxiliary_rbt_rotate_left(rbt_node_t * root, rbt_node_t * node);
rbt_node_t * auxiliary_rbt_rotate_right(rbt_node_t * root, rbt_node_t * node);
void auxiliary_release_red_black_tree(rbt_node_t * root);
int auxiliary_validator(rbt_node_t * root);

int default_compare(KeyType a, KeyType b)
{
return (a - b);
}

/* implementations of functions' */
static pfn_cmp default_cmp = &default_compare;
rbt_handle_t create_red_black_tree(pfn_cmp compare)
{
red_black_tree_t * tree;
if (!compare)
compare = default_cmp;
tree = (red_black_tree_t *)malloc(sizeof(red_black_tree_t));
if (!tree)
return NULL;
tree->root_ = nil_;
tree->cmp_ = compare;

return (rbt_handle_t)tree;
}

void release_red_black_tree(rbt_handle_t root)
{
red_black_tree_t * tree = (red_black_tree_t *)root;
if (tree)
{
auxiliary_release_red_black_tree(tree->root_);
free(tree);
}
}

bool rbt_is_valid(rbt_handle_t rbtree)
{
red_black_tree_t * tree = (red_black_tree_t *)rbtree;
if (!tree)
return false;
return (auxiliary_validator(tree->root_) >= 0);
}

RbtStatus rbt_find(rbt_handle_t rbtree, KeyType key)
{
red_black_tree_t * tree = (red_black_tree_t *)rbtree;
if (!tree)
return RBT_RBTREE_IS_NULL;
if (auxiliary_rbt_find(tree->root_, key, tree->cmp_) != nil_)
return RBT_SUCCESS;
else
return RBT_KEY_NONE_EXISTED;
}

RbtStatus rbt_insert(rbt_handle_t rbtree, KeyType key, ValueType value)
{
red_black_tree_t * tree = (red_black_tree_t *)rbtree;
rbt_node_t * node, * p;
if (!tree)
return RBT_RBTREE_IS_NULL;
node = create_rbt_node(key, value);
if (node == nil_)
return RBT_OUT_OF_MEMORY;

if (tree->root_ == nil_)
{
tree->root_ = node;
return RBT_SUCCESS;
}
p = auxiliary_rbt_insert(tree->root_, node, tree->cmp_);
if (p != node)
{
free(node);
return RBT_KEY_EXISTED;
}
node->color_ = RED;
tree->root_ = auxiliary_rbt_insert_fixup(tree->root_, node);

return RBT_SUCCESS;
}

RbtStatus rbt_remove(rbt_handle_t rbtree, KeyType key, ValueType * value)
{
red_black_tree_t * tree = (red_black_tree_t *)rbtree;
rbt_node_t * node;

if (!tree)
return RBT_RBTREE_IS_NULL;

if (tree->root_ == nil_)
return RBT_KEY_NONE_EXISTED;
node = auxiliary_rbt_find(tree->root_, key, tree->cmp_);
if (node == nil_)
return RBT_KEY_NONE_EXISTED;
tree->root_ = auxiliary_rbt_remove(tree->root_, node, tree->cmp_);

if (value)
* value = node->value_;

return RBT_SUCCESS;
}

rbt_node_t * create_rbt_node(KeyType key, ValueType value)
{
rbt_node_t * node = (rbt_node_t *)malloc(sizeof(rbt_node_t));
if (node)
{
node->father_ = nil_;
node->left_ = nil_;
node->right_ = nil_;
node->color_ = BLACK;
node->key_ = key;
node->value_ = value;
}
return node;
}

void auxiliary_release_red_black_tree(rbt_node_t * root)
{
if (root == nil_)
return;
auxiliary_release_red_black_tree(root->left_);
auxiliary_release_red_black_tree(root->right_);
free(root);
}

int auxiliary_validator(rbt_node_t * root)
{
int ldepth, rdepth;

if (root == nil_)
return 0;
ldepth = auxiliary_validator(root->left_);
rdepth = auxiliary_validator(root->right_);

if (ldepth < 0 || rdepth < 0)
return -1;

if (ldepth != rdepth)
{
printf( "/n/tViolation found! key: %s, color: %s",
root->key_, (root->color_ == RED)? "red": "black");
return -1;
}

if (root->color_ == BLACK)
return (ldepth + 1);
return ldepth;
}

rbt_node_t * auxiliary_rbt_find(rbt_node_t * root, KeyType key, pfn_cmp cmp)
{
int ret;

if (root == nil_)
return nil_;
ret = cmp(root->key_, key);
if (ret == 0)
return root;
else if (ret < 0)
return auxiliary_rbt_find(root->right_, key, cmp);
else
return auxiliary_rbt_find(root->left_, key, cmp);
}

rbt_node_t * auxiliary_rbt_rotate_left(rbt_node_t * root, rbt_node_t * node)
{
rbt_node_t * p;
if (!node || !root || root == nil_ || node == nil_)
return root;

p = node->right_;
if (p == nil_)
return root;

node->right_ = p->left_;
if (p->left_ != nil_)
p->left_->father_ = node;
p->father_ = node->father_;

if (node->father_ == nil_)
root = p;
else if (node->father_ != nil_)
{
if (node == node->father_->left_)
node->father_->left_ = p;
else
node->father_->right_ = p;
}

p->left_ = node;
node->father_ = p;

return root;
}

/* rotate right
*
*
*
*
*
* */
rbt_node_t * auxiliary_rbt_rotate_right(rbt_node_t * root, rbt_node_t * node)
{
rbt_node_t * p;

if (!node || !root || node == nil_ || root == nil_)
return root;

p = node->left_;
if (p == nil_)
return root;

node->left_ = p->right_;
if (p->right_ != nil_)
p->right_->father_ = node;
p->father_ = node->father_;

if (node->father_ == nil_)
root = p;
else if (node->father_ != nil_)
{
if (node == node->father_->left_)
node->father_->left_ = p;
else
node->father_->right_ = p;
}

p->right_ = node;
node->father_ = p;

return root;
}

/* Adjust the tree after inserting a red node so that it will satisify the 5 property of red black tree */
rbt_node_t * auxiliary_rbt_insert_fixup(rbt_node_t * root, rbt_node_t * node)
{
rbt_node_t * uncle;

if (root == nil_ || node == nil_)
return root;

uncle = nil_;
while (node != root && node->father_->color_ == RED) /* violate property 4 */
{
/*
* Firstly, determine current node's father is its grandfather's left son or right son,
* in each circumstance there existed 3 cases:
* 1. current node's father's sibling is a red node
* 2. current node is its father's left or right son
* 3. current node is rule 2's sibling
*
* */
if (node->father_ == node->father_->father_->left_)
{
uncle = node->father_->father_->right_;
if (uncle->color_ == RED)
{
/*
* case 1:
* If its father's sibling (i.e. uncle) is a red node
* then set its father and uncle's color to black
* and set its grandfather's color to red
* thus maintaining property 5 and solve the violation of property 4
*
* */
uncle->color_ = BLACK;
node->father_->color_ = BLACK;
node->father_->father_->color_ = RED;
node = node->father_->father_;
}else{
/*
* case 2:
* If it is its father's right son
* change current node to its father and rotate left
* while preserving property 5
*
* */
if (node == node->father_->right_)
{
node = node->father_;
root = auxiliary_rbt_rotate_left(root, node);
}
/*
* case 3:
* Otherwise, color its father with black and grandfather with red
* and then rotate right
*
* */
node->father_->father_->color_ = RED;
node->father_->color_ = BLACK;
root = auxiliary_rbt_rotate_right(root, node->father_->father_);
}
}else{
/*
* In this circumstance, the situation is
* same as above clause, so just exchange
* above clause's left and right
*
* */
uncle = node->father_->father_->left_;
if (uncle->color_ == RED)
{
uncle->color_ = BLACK;
node->father_->color_ = BLACK;
node->father_->father_->color_ = RED;
node = node->father_->father_;
}else{
if (node == node->father_->left_)
{
node = node->father_;
root = auxiliary_rbt_rotate_right(root, node);
}
node->father_->father_->color_ = RED;
node->father_->color_ = BLACK;
root = auxiliary_rbt_rotate_left(root, node->father_->father_);
}
}
}

root->color_ = BLACK;
return root;
}

rbt_node_t * auxiliary_rbt_insert(rbt_node_t * root, rbt_node_t * node, pfn_cmp cmp)
{
int ret;

if (!root || !node || node == nil_)
return root;

ret = cmp(root->key_, node->key_);
if (ret == 0)
return root;
else if (ret < 0)
{
if (root->right_ == nil_)
{
root->right_ = node;
node->father_ = root;
}
else
return auxiliary_rbt_insert(root->right_, node, cmp);
}else{
if (root->left_ == nil_)
{
root->left_ = node;
node->father_ = root;
}
else
return auxiliary_rbt_insert(root->left_, node, cmp);
}

return node;
}

rbt_node_t * auxiliary_rbt_remove(rbt_node_t * root, rbt_node_t * node, pfn_cmp cmp)
{
rbt_node_t * child = nil_;
rbt_node_t * parent = nil_;
rbt_node_t * old = node;

if (!root || root == nil_ || !node || node == nil_)
return root;

if (node->left_ == nil_)
child = node->right_;
else if (node->right_ == nil_)
child = node->left_;
else
{
node = node->right_;
while (node->left_ != nil_) /* find the leftmost node */
node = node->left_;
child = node->right_;
}
//if (child != nil_)
child->father_ = node->father_;

if (nil_ == node->father_)
root = child;
else
{
if (node->father_->left_ == node)
node->father_->left_ = child;
else
node->father_->right_ = child;
}

if (old != node)
{
KeyType ktmp;
ValueType vtmp;

ktmp = old->key_;
old->key_ = node->key_;
node->key_ = ktmp;

vtmp = old->value_;
old->value_ = node->value_;
node->value_ = vtmp;
}

if (node->color_ == BLACK)
root = auxiliary_rbt_remove_fixup(root, child);

return root;
}

/*
* Adjust the tree after deleting a black node so that
* it will satisify the 5 property of red black tree
*
* */
rbt_node_t * auxiliary_rbt_remove_fixup(rbt_node_t * root, rbt_node_t * node)
{
rbt_node_t * sibling = nil_;

if (!root || !node || root == nil_)
return root;

while (node != root && node->color_ == BLACK)
{
/*
* Firstly determing current node is his father's
* left or right son, and in both circumstances,
* there exist 4 cases:
* 1. current node's sibling's color is red
* 2. current node's sibling's color is black and
*	its sibling's two son are both black
* 3. current node's sibling's right son is black
* 4. current node's sibling's left son is black
*
* After case 1, the situation will convert to case 2, 3, 4
* only case 2 will continue to loop
*
* whatever the case is, make sure current's node's descendant's MUST
* satisfy the 5 properties of red black tree
*
* */
if (node == node->father_->left_)
{
sibling = node->father_->right_;
if (sibling->color_ == RED)
{
/*
* case 1:
* Set sibling's color to black and father to red
* and then rotate left, thus converting case 1
* to following case 2, 3 or 4
*
* */
sibling->color_ = BLACK;
node->father_->color_ = RED;
root = auxiliary_rbt_rotate_left(root, node->father_);
sibling = node->father_->right_;
}
if (sibling->left_->color_ == BLACK && sibling->right_->color_ == BLACK)
{
/*
* case 2:
* sibling's two sons are black so change sibling's color
* to red and move current node upward so as to loop
*
* */
sibling->color_ = RED;
node = node->father_;
} else{
/*
* case 3:
* Set sibling's left son to black and sibling to red
* then rotate right while preserving property 5
*
* */
if (sibling->right_->color_ == BLACK)
{
sibling->left_->color_ = BLACK;
sibling->color_ = RED;
root = auxiliary_rbt_rotate_right(root, sibling);
sibling = node->father_->right_;
}
/*
* case 4:
* sibling inherit node's father's color, then set node's father
* and sibling's right son to black, secondly rotate right
* in the end set node to root and terminate the loop
*
* */
sibling->color_ = node->father_->color_;
node->father_->color_ = BLACK;
sibling->right_->color_ = BLACK;
root = auxiliary_rbt_rotate_left(root, node->father_);
node = root;
}
}else{
/*
* In this circumstance, the situation is
* same as above clause, so just exchange
* above clause's left and right
*
* */
sibling = node->father_->left_;
if (sibling->color_ == RED)
{
sibling->color_ = BLACK;
node->father_->color_ = RED;
root = auxiliary_rbt_rotate_right(root, node->father_);
sibling = node->father_->left_;
}
if (sibling->left_->color_ == BLACK && sibling->right_->color_ == BLACK)
{
sibling->color_ = RED;
node = node->father_;
}else{
if (sibling->left_->color_ == BLACK)
{
sibling->right_->color_ = BLACK;
sibling->color_ = RED;
root = auxiliary_rbt_rotate_left(root, sibling);
sibling = node->father_->left_;
}
sibling->color_ = node->father_->color_;
node->father_->color_ = BLACK;
sibling->left_->color_ = BLACK;
root = auxiliary_rbt_rotate_right(root, node->father_);
node = root;
}
}
}
node->color_ = BLACK;
return root;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: