红黑树(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
rbtree.c
关于红黑树的介绍,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; }
相关文章推荐
- 数据结构 - 红黑树(Red Black Tree)删除详解与实现(Java)
- 红黑树(Red Black Tree) - Flex实现
- 红黑树(RedBlackTree),平衡树(BalancedTree),SkipList 的实现
- 红黑树与C实现算法 - RedBlackTree.c
- 红黑树与C实现算法 - RedBlackTree.c
- 红黑树(RedBlackTree)实现
- 自平衡二叉查找树(二)-----------红黑树(redblack tree)分析和代码实现
- [转载] 红黑树(Red Black Tree)- 对于 JDK TreeMap的实现
- 红黑树(red black tree) Common Lisp 实现
- 红黑树(Red BlackTree)的实现
- 红黑树(Red-Black Tree)
- 红黑树(Red Black Tree)
- C++数据结构 之 红黑树_Red Black Tree
- 红黑树(Red Black Tree)
- 《算法导论》读书笔记——红黑树(Red Black Tree)【for_wind】
- 红黑树(Red Black Tree)
- 红黑树(Red Black Tree)
- red_black_tree的一个实现(c/c++)
- 红黑树(Red Black Tree)
- 红黑树(RedblackTree)上--增加节点