红黑树与C实现算法
cheungmine
本文全部内容摘自互联网,作者根据需要做了修改和补充,最主要的是提供了对set的支持,并且给出完整的测试用例。
红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,他称之为"对称二叉B树",它现代的名字是在 Leo J. Guibas 和 Robert Sedgewick 于1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
红黑树是一种很有意思的平衡检索树。它的统计性能要好于平衡二叉树(有些书籍根据作者姓名,Adelson-Velskii和Landis,将其称为AVL-树),因此,红黑树在很多地方都有应用。在C++ STL中,很多部分(目前包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。
红黑树的实现代码如下(red_black_tree.h,red_black_tree.c和测试文件rbtree_test.c):
view plaincopy to clipboardprint?
/******************************************************************************
* red_black_tree.h *
* Download From: *
* http://www.cs.tau.ac.il/~efif/courses/Software1_Summer_03/code/rbtree/ *
* Last Edited by: *
* cheungmine *
* 2010-8 *
* Container class for a red-black tree: A binary tree that satisfies the *
* following properties: *
* 1. Each node has a color, which is either red or black. *
* 2. A red node cannot have a red parent. *
* 3. The number of black nodes from every path from the tree root to a leaf *
* is the same for all tree leaves (it is called the 'black depth' of the *
* tree). *
* Due to propeties 2-3, the depth of a red-black tree containing n nodes *
* is bounded by 2*log_2(n). *
* *
* The red_black_tree_t template requires two template parmeters: *
* - The contained TYPE class represents the objects stored in the tree. *
* It has to support the copy constructor and the assignment operator *
* (operator=). *
* *
* - pfcbRBTreeCompFunc is a functor used to define the order of objects of *
* class TYPE: *
* This class has to support an operator() that recieves two objects from *
* the TYPE class and returns a negative, zero or a positive integer, *
* depending on the comparison result. *
******************************************************************************/
#ifndef RED_BLACK_TREE_H
#define RED_BLACK_TREE_H
/*!
* Define RBTREE_SUPPORTS_MULTI_OBJECTS for supporting mapset (multi-key-map)
* if RBTREE_SUPPORTS_MULTI_OBJECTS defined, object must inherit from struct
* rbtree_object_base. That means the first member of object must be a struct
* pointer to next possible object if it has.
*
* #define RBTREE_SUPPORTS_MULTI_OBJECTS
*/
#define RBTREE_SUPPORTS_MULTI_OBJECTS
#ifdef RBTREE_SUPPORTS_MULTI_OBJECTS
typedef struct _rbtree_object_base {
struct _rbtree_object_base *__next_object;
}rbtree_object_base;
#endif
/*! Color enumeration for nodes of red-black tree */
typedef enum _red_black_color_enum
{
rbcRed,
rbcBlack
} red_black_color_enum;
/*! Representation of a node in a red-black tree */
typedef struct _red_black_node_t {
void * object; /* the stored object user defined */
red_black_color_enum color; /* the color of the node */
struct _red_black_node_t * parent; /* points to the parent node */
struct _red_black_node_t * right; /* points to the right child */
struct _red_black_node_t * left; /* points to the left child */
} red_black_node_t;
/*! Callback function prototype for comparing objects */
typedef int (pfcbRBTreeCompFunc)(void *object1, void *object2);
/*! Callback function prototype for traverse objects */
typedef void(pfcbRBTreeOperFunc)(void *object, void *param);
/*! Construct of a red-black tree node
* param object The object stored in the node
* param color The color of the node
*/
extern red_black_node_t * rbnode_construct(void * object, red_black_color_enum color);
/*! Recursive destructor for the entire sub-tree */
extern void rbnode_destruct(red_black_node_t * node);
/*! Calculate the depth of the sub-tree spanned by the given node
* param node The sub-tree root
* return The sub-tree depth
*/
extern int rbnode_depth(red_black_node_t * node);
/*! Get the leftmost node in the sub-tree spanned by the given node
* param node The sub-tree root
* return The sub-tree minimum
*/
extern red_black_node_t * rbnode_minimum(red_black_node_t * node);
/*! Get the rightmost node in the sub-tree spanned by the given node
* param node The sub-tree root
* return The sub-tree maximum
*/
extern red_black_node_t * rbnode_maximum(red_black_node_t * node);
/*! Replace the object */
extern void rbnode_replace(red_black_node_t * node, void * object);
/*! Get the next node in the tree (according to the tree order)
* param node The current node
* return The successor node, or NULL if node is the tree maximum
*/
extern red_black_node_t * rbnode_successor(red_black_node_t * node);
/*! Get the previous node in the tree (according to the tree order)
* param node The current node
* return The predecessor node, or NULL if node is the tree minimum
*/
extern red_black_node_t * rbnode_predecessor(red_black_node_t * node);
/*! Duplicate the entire sub-tree rooted at the given node
* param node The sub-tree root
* return A pointer to the duplicated sub-tree root
*/
extern red_black_node_t * rbnode_duplicate(red_black_node_t * node);
/*! Traverse a red-black sub-tree left first
* param node The sub-tree root
* param op The operation to perform on each object in the sub-tree
*/
extern void rbnode_traverse(red_black_node_t *node, pfcbRBTreeOperFunc *opFunc, void *param);
/*! Traverse a red-black sub-tree right first
*/
extern void rbnode_traverse_right(red_black_node_t *node, pfcbRBTreeOperFunc *opFunc, void*param);
/*! Representation of a red-black tree */
typedef struct _red_black_tree_t {
red_black_node_t * root; /* pointer to the tree root */
int iSize; /* number of objects stored */
pfcbRBTreeCompFunc * comp; /* compare function */
} red_black_tree_t;
/*! Initialize a red-black tree with a comparision function
* param tree The tree
* param comp The comparision function
*/
void rbtree_init(red_black_tree_t * tree, pfcbRBTreeCompFunc * comp);
/*! Construct a red-black tree with a comparison object
* param comp A pointer to the comparison object to be used by the tree
* return The newly constructed tree
*/
red_black_tree_t * rbtree_construct(pfcbRBTreeCompFunc * comp);
/*! Clean a red-black tree [takes O(n) operations]
* param tree The tree
*/
extern void rbtree_clean(red_black_tree_t * tree);
/*! Destruct a red-black tree
* param tree The tree
*/
extern void rbtree_destruct(red_black_tree_t * tree);
/*! Get the size of the tree [takes O(1) operations]
* param tree The tree
* return The number of objects stored in the tree
*/
extern int rbtree_size(red_black_tree_t * tree);
/*! Get the depth of the tree [takes O(n) operations]
* param tree The tree
* return The length of the longest path from the root to a leaf node
*/
extern int rbtree_depth(red_black_tree_t * tree);
/*! Check whether the tree contains an object [takes O(log n) operations]
* param tree The tree
* param object The query object
* return (true) if an equal object is found in the tree, otherwise (false)
*/
extern int rbtree_contains(red_black_tree_t * tree, void * object);
/*! Insert an object to the tree [takes O(log n) operations]
* param tree The tree
* param object The object to be inserted
* return the inserted object node
*/
extern red_black_node_t * rbtree_insert(red_black_tree_t * tree, void * object);
/*! Insert an unique object to the tree */
extern red_black_node_t * rbtree_insert_unique(red_black_tree_t * tree, void * object);
/*! Insert a new object to the tree as the a successor of a given node
* param tree The tree
* return The new node
*/
extern red_black_node_t * insert_successor_at(red_black_tree_t * tree,
red_black_node_t * at_node,
void * object);
/*! Insert a new object to the tree as the a predecessor of a given node
* param tree The tree
* return The new node
*/
extern red_black_node_t * insert_predecessor_at(red_black_tree_t * tree,
red_black_node_t * at_node,
void * object);
/*! Remove an object from the tree [takes O(log n) operations]
* param tree The tree
* param object The object to be removed
* pre The object should be contained in the tree
*/
extern void rbtree_remove(red_black_tree_t * tree, void * object);
/*! Get a handle to the tree minimum [takes O(log n) operations]
* param tree The tree
* return the minimal object in the tree, or a NULL if the tree is empty
*/
extern red_black_node_t * rbtree_minimum(red_black_tree_t * tree);
/*! Get a handle to the tree maximum [takes O(log n) operations]
* param tree The tree
* return the maximal object in the tree, or a NULL if the tree is empty
*/
extern red_black_node_t * rbtree_maximum(red_black_tree_t * tree);
/*! Get the next node in the tree (according to the tree order)
* [takes O(log n) operations at worst-case, but only O(1) amortized]
* param tree The tree
* param node The current object
* return The successor node, or a NULL, if we are at the tree maximum
*/
extern red_black_node_t * rbtree_successor(red_black_tree_t * tree,
red_black_node_t * node);
/*! Get the previous node in the tree (according to the tree order)
* [takes O(log n) operations at worst-case, but only O(1) amortized]
* param tree The tree
* param node The current object
* return The predecessor node, or a NULL, if we are at the tree minimum
*/
extern red_black_node_t * rbtree_predecessor(red_black_tree_t * tree,
red_black_node_t * node);
/*! Find a node that contains the given object
* param tree The tree
* param object The desired object
* return A node that contains the given object, or NULL if no such object
* is found in the tree
*/
extern red_black_node_t * rbtree_find(red_black_tree_t * tree, void * object);
/*! Remove the object stored in the given tree node
* param tree The tree
* param node The node storing the object to be removed from the tree
*/
extern void rbtree_remove_at(red_black_tree_t * tree, red_black_node_t * node);
/*! Left-rotate the sub-tree spanned by the given node
* param tree The tree
* param node The sub-tree root
*/
extern void rbtree_rotate_left(red_black_tree_t * tree, red_black_node_t * node);
/*! Right-rotate the sub-tree spanned by the given node
* param tree The tree
* param node The sub-tree root
*/
extern void rbtree_rotate_right(red_black_tree_t * tree, red_black_node_t * node);
/*!
* Fix-up the red-black tree properties after an insertion operation
* param tree The tree
* param node The node that has just been inserted to the tree
* pre The color of node must be red
*/
extern void rbtree_insert_fixup(red_black_tree_t * tree, red_black_node_t * node);
/*! Fix-up the red-black tree properties after a removal operation
* param tree The tree
* param node The child of the node that has just been removed from the tree
*/
extern void rbtree_remove_fixup(red_black_tree_t * tree, red_black_node_t * node);
/*! Traverse a red-black tree left first
* param tree The tree
* param op The operation to perform on every object of the tree (according to
* the tree order)
*/
extern void rbtree_traverse(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param);
#define rbtree_traverse_left rbtree_traverse
/*! Traverse a red-black tree right first */
extern void rbtree_traverse_right(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param);
#endif /* RED_BLACK_TREE_H */
/******************************************************************************
* red_black_tree.h *
* Download From: *
* http://www.cs.tau.ac.il/~efif/courses/Software1_Summer_03/code/rbtree/ *
* Last Edited by: *
* cheungmine *
* 2010-8 *
* Container class for a red-black tree: A binary tree that satisfies the *
* following properties: *
* 1. Each node has a color, which is either red or black. *
* 2. A red node cannot have a red parent. *
* 3. The number of black nodes from every path from the tree root to a leaf *
* is the same for all tree leaves (it is called the 'black depth' of the *
* tree). *
* Due to propeties 2-3, the depth of a red-black tree containing n nodes *
* is bounded by 2*log_2(n). *
* *
* The red_black_tree_t template requires two template parmeters: *
* - The contained TYPE class represents the objects stored in the tree. *
* It has to support the copy constructor and the assignment operator *
* (operator=). *
* *
* - pfcbRBTreeCompFunc is a functor used to define the order of objects of *
* class TYPE: *
* This class has to support an operator() that recieves two objects from *
* the TYPE class and returns a negative, zero or a positive integer, *
* depending on the comparison result. *
******************************************************************************/
#ifndef RED_BLACK_TREE_H
#define RED_BLACK_TREE_H
/*!
* Define RBTREE_SUPPORTS_MULTI_OBJECTS for supporting mapset (multi-key-map)
* if RBTREE_SUPPORTS_MULTI_OBJECTS defined, object must inherit from struct
* rbtree_object_base. That means the first member of object must be a struct
* pointer to next possible object if it has.
*
* #define RBTREE_SUPPORTS_MULTI_OBJECTS
*/
#define RBTREE_SUPPORTS_MULTI_OBJECTS
#ifdef RBTREE_SUPPORTS_MULTI_OBJECTS
typedef struct _rbtree_object_base {
struct _rbtree_object_base *__next_object;
}rbtree_object_base;
#endif
/*! Color enumeration for nodes of red-black tree */
typedef enum _red_black_color_enum
{
rbcRed,
rbcBlack
} red_black_color_enum;
/*! Representation of a node in a red-black tree */
typedef struct _red_black_node_t {
void * object; /* the stored object user defined */
red_black_color_enum color; /* the color of the node */
struct _red_black_node_t * parent; /* points to the parent node */
struct _red_black_node_t * right; /* points to the right child */
struct _red_black_node_t * left; /* points to the left child */
} red_black_node_t;
/*! Callback function prototype for comparing objects */
typedef int (pfcbRBTreeCompFunc)(void *object1, void *object2);
/*! Callback function prototype for traverse objects */
typedef void(pfcbRBTreeOperFunc)(void *object, void *param);
/*! Construct of a red-black tree node
* param object The object stored in the node
* param color The color of the node
*/
extern red_black_node_t * rbnode_construct(void * object, red_black_color_enum color);
/*! Recursive destructor for the entire sub-tree */
extern void rbnode_destruct(red_black_node_t * node);
/*! Calculate the depth of the sub-tree spanned by the given node
* param node The sub-tree root
* return The sub-tree depth
*/
extern int rbnode_depth(red_black_node_t * node);
/*! Get the leftmost node in the sub-tree spanned by the given node
* param node The sub-tree root
* return The sub-tree minimum
*/
extern red_black_node_t * rbnode_minimum(red_black_node_t * node);
/*! Get the rightmost node in the sub-tree spanned by the given node
* param node The sub-tree root
* return The sub-tree maximum
*/
extern red_black_node_t * rbnode_maximum(red_black_node_t * node);
/*! Replace the object */
extern void rbnode_replace(red_black_node_t * node, void * object);
/*! Get the next node in the tree (according to the tree order)
* param node The current node
* return The successor node, or NULL if node is the tree maximum
*/
extern red_black_node_t * rbnode_successor(red_black_node_t * node);
/*! Get the previous node in the tree (according to the tree order)
* param node The current node
* return The predecessor node, or NULL if node is the tree minimum
*/
extern red_black_node_t * rbnode_predecessor(red_black_node_t * node);
/*! Duplicate the entire sub-tree rooted at the given node
* param node The sub-tree root
* return A pointer to the duplicated sub-tree root
*/
extern red_black_node_t * rbnode_duplicate(red_black_node_t * node);
/*! Traverse a red-black sub-tree left first
* param node The sub-tree root
* param op The operation to perform on each object in the sub-tree
*/
extern void rbnode_traverse(red_black_node_t *node, pfcbRBTreeOperFunc *opFunc, void *param);
/*! Traverse a red-black sub-tree right first
*/
extern void rbnode_traverse_right(red_black_node_t *node, pfcbRBTreeOperFunc *opFunc, void*param);
/*! Representation of a red-black tree */
typedef struct _red_black_tree_t {
red_black_node_t * root; /* pointer to the tree root */
int iSize; /* number of objects stored */
pfcbRBTreeCompFunc * comp; /* compare function */
} red_black_tree_t;
/*! Initialize a red-black tree with a comparision function
* param tree The tree
* param comp The comparision function
*/
void rbtree_init(red_black_tree_t * tree, pfcbRBTreeCompFunc * comp);
/*! Construct a red-black tree with a comparison object
* param comp A pointer to the comparison object to be used by the tree
* return The newly constructed tree
*/
red_black_tree_t * rbtree_construct(pfcbRBTreeCompFunc * comp);
/*! Clean a red-black tree [takes O(n) operations]
* param tree The tree
*/
extern void rbtree_clean(red_black_tree_t * tree);
/*! Destruct a red-black tree
* param tree The tree
*/
extern void rbtree_destruct(red_black_tree_t * tree);
/*! Get the size of the tree [takes O(1) operations]
* param tree The tree
* return The number of objects stored in the tree
*/
extern int rbtree_size(red_black_tree_t * tree);
/*! Get the depth of the tree [takes O(n) operations]
* param tree The tree
* return The length of the longest path from the root to a leaf node
*/
extern int rbtree_depth(red_black_tree_t * tree);
/*! Check whether the tree contains an object [takes O(log n) operations]
* param tree The tree
* param object The query object
* return (true) if an equal object is found in the tree, otherwise (false)
*/
extern int rbtree_contains(red_black_tree_t * tree, void * object);
/*! Insert an object to the tree [takes O(log n) operations]
* param tree The tree
* param object The object to be inserted
* return the inserted object node
*/
extern red_black_node_t * rbtree_insert(red_black_tree_t * tree, void * object);
/*! Insert an unique object to the tree */
extern red_black_node_t * rbtree_insert_unique(red_black_tree_t * tree, void * object);
/*! Insert a new object to the tree as the a successor of a given node
* param tree The tree
* return The new node
*/
extern red_black_node_t * insert_successor_at(red_black_tree_t * tree,
red_black_node_t * at_node,
void * object);
/*! Insert a new object to the tree as the a predecessor of a given node
* param tree The tree
* return The new node
*/
extern red_black_node_t * insert_predecessor_at(red_black_tree_t * tree,
red_black_node_t * at_node,
void * object);
/*! Remove an object from the tree [takes O(log n) operations]
* param tree The tree
* param object The object to be removed
* pre The object should be contained in the tree
*/
extern void rbtree_remove(red_black_tree_t * tree, void * object);
/*! Get a handle to the tree minimum [takes O(log n) operations]
* param tree The tree
* return the minimal object in the tree, or a NULL if the tree is empty
*/
extern red_black_node_t * rbtree_minimum(red_black_tree_t * tree);
/*! Get a handle to the tree maximum [takes O(log n) operations]
* param tree The tree
* return the maximal object in the tree, or a NULL if the tree is empty
*/
extern red_black_node_t * rbtree_maximum(red_black_tree_t * tree);
/*! Get the next node in the tree (according to the tree order)
* [takes O(log n) operations at worst-case, but only O(1) amortized]
* param tree The tree
* param node The current object
* return The successor node, or a NULL, if we are at the tree maximum
*/
extern red_black_node_t * rbtree_successor(red_black_tree_t * tree,
red_black_node_t * node);
/*! Get the previous node in the tree (according to the tree order)
* [takes O(log n) operations at worst-case, but only O(1) amortized]
* param tree The tree
* param node The current object
* return The predecessor node, or a NULL, if we are at the tree minimum
*/
extern red_black_node_t * rbtree_predecessor(red_black_tree_t * tree,
red_black_node_t * node);
/*! Find a node that contains the given object
* param tree The tree
* param object The desired object
* return A node that contains the given object, or NULL if no such object
* is found in the tree
*/
extern red_black_node_t * rbtree_find(red_black_tree_t * tree, void * object);
/*! Remove the object stored in the given tree node
* param tree The tree
* param node The node storing the object to be removed from the tree
*/
extern void rbtree_remove_at(red_black_tree_t * tree, red_black_node_t * node);
/*! Left-rotate the sub-tree spanned by the given node
* param tree The tree
* param node The sub-tree root
*/
extern void rbtree_rotate_left(red_black_tree_t * tree, red_black_node_t * node);
/*! Right-rotate the sub-tree spanned by the given node
* param tree The tree
* param node The sub-tree root
*/
extern void rbtree_rotate_right(red_black_tree_t * tree, red_black_node_t * node);
/*!
* Fix-up the red-black tree properties after an insertion operation
* param tree The tree
* param node The node that has just been inserted to the tree
* pre The color of node must be red
*/
extern void rbtree_insert_fixup(red_black_tree_t * tree, red_black_node_t * node);
/*! Fix-up the red-black tree properties after a removal operation
* param tree The tree
* param node The child of the node that has just been removed from the tree
*/
extern void rbtree_remove_fixup(red_black_tree_t * tree, red_black_node_t * node);
/*! Traverse a red-black tree left first
* param tree The tree
* param op The operation to perform on every object of the tree (according to
* the tree order)
*/
extern void rbtree_traverse(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param);
#define rbtree_traverse_left rbtree_traverse
/*! Traverse a red-black tree right first */
extern void rbtree_traverse_right(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param);
#endif /* RED_BLACK_TREE_H */
view plaincopy to clipboardprint?
01./******************************************************************************
02.* red_black_tree.c *
03.* Download From: *
04.* http://www.cs.tau.ac.il/~efif/courses/Software1_Summer_03/code/rbtree/ *
05.* Last Edited by: cheungmine *
06.******************************************************************************/
07.#include <stdio.h>
08.#include <stdlib.h>
09.#include <assert.h>
10.#include "red_black_tree.h"
11./*!
12. * Operations on red_black_node_t struct
13. */
14./* Construct a red-black tree node */
15.red_black_node_t * rbnode_construct(void * object, red_black_color_enum color)
16.{
17. red_black_node_t * node = (red_black_node_t *) malloc(sizeof(red_black_node_t));
18. if (!node) {
19. fprintf(stderr, "Not enough memory!\n");
20. return NULL;
21. }
22. node->object = object;
23. node->color = color;
24. node->parent = node->right = node->left = NULL;
25. return node;
26.}
27./* Destructor of a red-black tree node */
28.void rbnode_destruct(red_black_node_t * node)
29.{
30. if (!node) return;
31. rbnode_destruct(node->right);
32. rbnode_destruct(node->left);
33. free(node);
34.}
35./* Calculate the depth of the subtree spanned by a given node */
36.int rbnode_depth(red_black_node_t * node)
37.{
38. /* Recursively calculate the depth of the left and right sub-trees */
39. int iRightDepth = (node->right) ? rbnode_depth(node->right) : 0;
40. int iLeftDepth = (node->left) ? rbnode_depth(node->left) : 0;
41. /* Return the maximal child depth + 1 (the current node) */
42. return ((iRightDepth > iLeftDepth) ? (iRightDepth + 1) : (iLeftDepth + 1));
43.}
44./* Return the leftmost leaf in the tree */
45.red_black_node_t * rbnode_minimum(red_black_node_t * node)
46.{
47. while (node->left)
48. node = node->left;
49. return node;
50.}
51./* Return the rightmost leaf in the tree */
52.red_black_node_t * rbnode_maximum(red_black_node_t * node)
53.{
54. while (node->right)
55. node = node->right;
56. return node;
57.}
58./* Replace the object */
59.void rbnode_replace(red_black_node_t * node, void * object)
60.{
61. /* Make sure the replacement does not violate the tree order */
62. /* Replace the object at node */
63. node->object = object;
64.}
65.
66./* Get the next node in the tree (according to the tree order) */
67.red_black_node_t * rbnode_successor(red_black_node_t * node)
68.{
69. red_black_node_t * succ_node;
70. if (node->right) {
71. /* If there is a right child, the successor is the minimal object in
72. * the sub-tree spanned by this child.
73. */
74. succ_node = node->right;
75. while (succ_node->left)
76. succ_node = succ_node->left;
77. }
78. else {
79. /* Otherwise, go up the tree until reaching the parent from the left
80. * direction.
81. */
82. red_black_node_t * prev_node = node;
83. succ_node = node->parent;
84. while (succ_node && prev_node == succ_node->right) {
85. prev_node = succ_node;
86. succ_node = succ_node->parent;
87. }
88. }
89. return (succ_node);
90.}
91./* Get the previous node in the tree (according to the tree order) */
92.red_black_node_t * rbnode_predecessor(red_black_node_t * node)
93.{
94. red_black_node_t * pred_node;
95. if (node->left) {
96. /* If there is a left child, the predecessor is the maximal object in
97. * the sub-tree spanned by this child.
98. */
99. pred_node = node->left;
100. while (pred_node->right)
101. pred_node = pred_node->right;
102. } else {
103. /* Otherwise, go up the tree until reaching the parent from the right
104. * direction.
105. */
106. red_black_node_t * prev_node = node;
107. pred_node = node->parent;
108. while (pred_node && prev_node == pred_node->left) {
109. prev_node = pred_node;
110. pred_node = pred_node->parent;
111. }
112. }
113. return (pred_node);
114.}
115./* Return a pointer to a duplication of the given node */
116.red_black_node_t * rbnode_duplicate(red_black_node_t * node)
117.{
118. /* Create a node of the same color, containing the same object */
119. red_black_node_t * dup_node = rbnode_construct(node->object, node->color);
120. if (!dup_node) return NULL;
121. /* Duplicate the children recursively */
122. if (node->right) {
123. dup_node->right = rbnode_duplicate (node->right);
124. dup_node->right->parent = dup_node;
125. } else {
126. dup_node->right = NULL;
127. }
128. if (node->left) {
129. dup_node->left = rbnode_duplicate(node->left);
130. dup_node->left->parent = dup_node;
131. } else {
132. dup_node->left = NULL;
133. }
134. return dup_node; /* Return the duplicated node */
135.}
136./* Traverse a red-black subtree */
137.void rbnode_traverse(red_black_node_t * node, pfcbRBTreeOperFunc * opFunc, void* param)
138.{
139. if (!node) return;
140. rbnode_traverse(node->left, opFunc, param);
141. opFunc(node->object, param);
142. rbnode_traverse(node->right, opFunc, param);
143.}
144./* Right-first traverse a red-black subtree */
145.void rbnode_traverse_right(red_black_node_t * node, pfcbRBTreeOperFunc * opFunc, void* param)
146.{
147. if (!node) return;
148. rbnode_traverse_right(node->right, opFunc, param);
149. opFunc(node->object, param);
150. rbnode_traverse_right(node->left, opFunc, param);
151.}
152./*
153. * Operations on red_black_tree_t struct
154. */
155./* Intialize a tree */
156.void rbtree_init(red_black_tree_t * tree, pfcbRBTreeCompFunc * comp)
157.{
158. tree->comp = comp;
159. tree->iSize = 0;
160. tree->root = NULL;
161.}
162./* Construct a tree given a comparison function */
163.red_black_tree_t * rbtree_construct(pfcbRBTreeCompFunc * comp)
164.{
165. red_black_tree_t * tree = (red_black_tree_t *) malloc(sizeof(red_black_tree_t));
166. if (!tree) {
167. fprintf(stderr, "Not enough memory!\n");
168. return NULL;
169. }
170. rbtree_init(tree, comp);
171. return tree;
172.}
173./* Remove all objects from a black-red tree */
174.void rbtree_clean(red_black_tree_t * tree)
175.{
176. if (tree->root)
177. rbnode_destruct(tree->root);
178. tree->root = NULL;
179. tree->iSize = 0;
180.}
181./* Destruct a red-black tree */
182.void rbtree_destruct(red_black_tree_t * tree)
183.{
184. rbtree_clean(tree);
185. free(tree);
186.}
187./* Returns the size of the tree */
188.int rbtree_size(red_black_tree_t * tree)
189.{
190. return tree->iSize;
191.}
192./* Returns the depth of the tree */
193.int rbtree_depth(red_black_tree_t * tree)
194.{
195. if (!(tree->root))
196. return 0;
197. return rbnode_depth(tree->root);
198.}
199./* Check whether the tree contains an object */
200.int rbtree_contains(red_black_tree_t * tree, void * object)
201.{
202. return (rbtree_find(tree, object) != NULL);
203.}
204./* Insert an object to the tree */
205.red_black_node_t * rbtree_insert(red_black_tree_t * tree, void * object)
206.{
207. int cmp;
208. red_black_node_t * cur_node;
209. red_black_node_t * new_node = NULL;
210.
211. if (!(tree->root)) {
212. /* Assign a new root node. Notice that the root is always black */
213. new_node = rbnode_construct(object, rbcBlack);
214. if (!new_node) return NULL;
215. tree->root = new_node;
216. tree->iSize = 1;
217. return new_node;
218. }
219. /* Find a place for the new object, and insert it as a red leaf */
220. cur_node = tree->root;
221.
222. while (cur_node) {
223. cmp = (*(tree->comp))(object, cur_node->object);
224.#ifdef RBTREE_SUPPORTS_MULTI_OBJECTS
225. if (cmp==0) {
226. if (cur_node->object != object)
227. ((rbtree_object_base*)cur_node->object)->__next_object = (rbtree_object_base*)object;
228. return cur_node;
229. }
230.#endif
231. /* Compare inserted object with the object stored in the current node */
232. if (cmp > 0) {
233. if (!(cur_node->left)) {
234. /* Insert the new leaf as the left child of the current node */
235. new_node = rbnode_construct(object, rbcRed);
236. if (!new_node) return NULL;
237. cur_node->left = new_node;
238. new_node->parent = cur_node;
239. cur_node = NULL; /* terminate the while loop */
240. } else {
241. cur_node = cur_node->left; /* Go to the left sub-tree */
242. }
243. } else {
244. if (!(cur_node->right)) {
245. /* Insert the new leaf as the right child of the current node */
246. new_node = rbnode_construct(object, rbcRed);
247. if (!new_node) return NULL;
248. cur_node->right = new_node;
249. new_node->parent = cur_node;
250. cur_node = NULL; /* terminate the while loop */
251. } else {
252. cur_node = cur_node->right; /* Go to the right sub-tree */
253. }
254. }
255. }
256. /* Mark that a new node was added */
257. tree->iSize++;
258. /* Fix up the tree properties */
259. rbtree_insert_fixup(tree, new_node);
260. return new_node;
261.}
262./* Insert an unique object to the tree */
263.red_black_node_t * rbtree_insert_unique(red_black_tree_t * tree, void * object)
264.{
265. int cmp;
266. red_black_node_t * cur_node;
267. red_black_node_t * new_node = NULL;
268.
269. if (!(tree->root)) {
270. /* Assign a new root node. Notice that the root is always black */
271. new_node = rbnode_construct(object, rbcBlack);
272. if (!new_node) return NULL;
273. tree->root = new_node;
274. tree->iSize = 1;
275. return new_node;
276. }
277. /* Find a place for the new object, and insert it as a red leaf */
278. cur_node = tree->root;
279. while (cur_node) {
280. cmp = (*(tree->comp))(object, cur_node->object);
281. if (cmp==0) {
282. /* there already has an object with the same id as object to be inserted */
283. return cur_node;
284. }
285. /* Compare inserted object with the object stored in the current node */
286. if (cmp > 0) {
287. if (!(cur_node->left)) {
288. /* Insert the new leaf as the left child of the current node */
289. new_node = rbnode_construct(object, rbcRed);
290. if (!new_node)
291. return NULL;
292. cur_node->left = new_node;
293. new_node->parent = cur_node;
294. cur_node = NULL; /* terminate the while loop */
295. } else {
296. cur_node = cur_node->left; /* Go to the left sub-tree */
297. }
298. } else {
299. if (!(cur_node->right)) {
300. /* Insert the new leaf as the right child of the current node */
301. new_node = rbnode_construct(object, rbcRed);
302. if (!new_node)
303. return NULL;
304. cur_node->right = new_node;
305. new_node->parent = cur_node;
306. cur_node = NULL; /* terminate the while loop */
307. } else {
308. cur_node = cur_node->right; /* Go to the right sub-tree */
309. }
310. }
311. }
312. /* Mark that a new node was added */
313. tree->iSize++;
314. /* Fix up the tree properties */
315. rbtree_insert_fixup(tree, new_node);
316. return new_node;
317.}
318./* Insert a new object to the tree as the a successor of a given node */
319.red_black_node_t * insert_successor_at(red_black_tree_t * tree,
320. red_black_node_t * at_node, void * object)
321.{
322. red_black_node_t * parent;
323. red_black_node_t * new_node;
324.
325. if (!(tree->root)) {
326. /* Assign a new root node. Notice that the root is always black */
327. new_node = rbnode_construct(object, rbcBlack);
328. if (!new_node) return NULL;
329. tree->root = new_node;
330. tree->iSize = 1;
331. return new_node;
332. }
333. /* Insert the new object as a red leaf, being the successor of node */
334. new_node = rbnode_construct(object, rbcRed);
335. if (!new_node) return NULL;
336. if (!at_node) {
337. /* The new node should become the tree minimum: Place is as the left
338. * child of the current minimal leaf.
339. */
340. parent = rbnode_minimum(tree->root);
341. parent->left = new_node;
342. } else {
343. /* Make sure the insertion does not violate the tree order */
344. /* In case given node has no right child, place the new node as its
345. * right child. Otherwise, place it at the leftmost position at the
346. * sub-tree rooted at its right side.
347. */
348. if (!at_node->right) {
349. parent = at_node;
350. parent->right = new_node;
351. } else {
352. parent = rbnode_minimum(at_node->right);
353. parent->left = new_node;
354. }
355. }
356. new_node->parent = parent;
357. /* Mark that a new node was added */
358. tree->iSize++;
359. /* Fix up the tree properties */
360. rbtree_insert_fixup(tree, new_node);
361. return new_node;
362.}
363./* Insert a new object to the tree as the a predecessor of a given node */
364.red_black_node_t * insert_predecessor_at(red_black_tree_t * tree,
365. red_black_node_t * at_node, void * object)
366.{
367. red_black_node_t * parent;
368. red_black_node_t * new_node;
369.
370. if (!(tree->root)) {
371. /* Assign a new root node. Notice that the root is always black */
372. new_node = rbnode_construct(object, rbcBlack);
373. if (!new_node) return NULL;
374. tree->root = new_node;
375. tree->iSize = 1;
376. return new_node;
377. }
378. /* Insert the new object as a red leaf, being the predecessor of at_node */
379. new_node = rbnode_construct(object, rbcRed);
380. if (!new_node) return NULL;
381. if (!at_node) {
382. /* The new node should become the tree maximum: Place is as the right
383. * child of the current maximal leaf.
384. */
385. parent = rbnode_maximum(tree->root);
386. parent->right = new_node;
387. } else {
388. /* Make sure the insertion does not violate the tree order */
389. /* In case given node has no left child, place the new node as its
390. * left child. Otherwise, place it at the rightmost position at the
391. * sub-tree rooted at its left side.
392. */
393. if (!(at_node->left)) {
394. parent = at_node;
395. parent->left = new_node;
396. } else {
397. parent = rbnode_maximum (at_node->left);
398. parent->right = new_node;
399. }
400. }
401. new_node->parent = parent;
402. /* Mark that a new node was added */
403. tree->iSize++;
404. /* Fix up the tree properties */
405. rbtree_insert_fixup(tree, new_node);
406. return new_node;
407.}
408./* Remove an object from the tree */
409.void rbtree_remove(red_black_tree_t * tree, void * object)
410.{
411. red_black_node_t * node = rbtree_find(tree, object); /* find the node */
412. rbtree_remove_at(tree, node); /* remove the node */
413.}
414./* Remove the object pointed by the given node. */
415.void rbtree_remove_at(red_black_tree_t * tree, red_black_node_t * node)
416.{
417. red_black_node_t * child = NULL;
418. /* In case of deleting the single object stored in the tree, free the root,
419. * thus emptying the tree.
420. */
421. if (tree->iSize == 1) {
422. rbnode_destruct(tree->root);
423. tree->root = NULL;
424. tree->iSize = 0;
425. return;
426. }
427. /* Remove the given node from the tree */
428. if (node->left && node->right) {
429. /* If the node we want to remove has two children, find its successor,
430. * which is the leftmost child in its right sub-tree and has at most
431. * one child (it may have a right child).
432. */
433. red_black_node_t * succ_node = rbnode_minimum(node->right);
434. /* Now physically swap node and its successor. Notice this may temporarily
435. * violate the tree properties, but we are going to remove node anyway.
436. * This way we have moved node to a position were it is more convinient
437. * to delete it.
438. */
439. int immediate_succ = (node->right == succ_node);
440. red_black_node_t * succ_parent = succ_node->parent;
441. red_black_node_t * succ_left = succ_node->left;
442. red_black_node_t * succ_right = succ_node->right;
443. red_black_color_enum succ_color = succ_node->color;
444. succ_node->parent = node->parent;
445. succ_node->left = node->left;
446. succ_node->right = immediate_succ ? node : node->right;
447. succ_node->color = node->color;
448. node->parent = immediate_succ ? succ_node : succ_parent;
449. node->left = succ_left;
450. node->right = succ_right;
451. node->color = succ_color;
452. if (!immediate_succ) {
453. if (succ_node == node->parent->left)
454. node->parent->left = node;
455. else
456. node->parent->right = node;
457. }
458. if (node->left)
459. node->left->parent = node;
460. if (node->right)
461. node->right->parent = node;
462. if (succ_node->parent) {
463. if (node == succ_node->parent->left)
464. succ_node->parent->left = succ_node;
465. else
466. succ_node->parent->right = succ_node;
467. } else {
468. tree->root = succ_node;
469. }
470. if (succ_node->left)
471. succ_node->left->parent = succ_node;
472. if (succ_node->right)
473. succ_node->right->parent = succ_node;
474. }
475. /* At this stage, the node we are going to remove has at most one child */
476. child = (node->left) ? node->left : node->right;
477. /* Splice out the node to be removed, by linking its parent straight to the
478. * removed node's single child.
479. */
480. if (child)
481. child->parent = node->parent;
482.
483. if (!(node->parent)) {
484. /* If we are deleting the root, make the child the new tree node */
485. tree->root = child;
486. } else {
487. /* Link the removed node parent to its child */
488. if (node == node->parent->left) {
489. node->parent->left = child;
490. } else {
491. node->parent->right = child;
492. }
493. }
494. /* Fix-up the red-black properties that may have been damaged: If we have
495. * just removed a black node, the black-depth property is no longer valid.
496. */
497. if (node->color == rbcBlack && child)
498. rbtree_remove_fixup(tree, child);
499. /* Delete the un-necessary node (we nullify both its children because the
500. * node's destructor is recursive).
501. */
502. node->left = NULL;
503. node->right = NULL;
504. free(node);
505. /* Descrease the number of objects in the tree */
506. tree->iSize--;
507.}
508./* Get the tree minimum */
509.red_black_node_t * rbtree_minimum(red_black_tree_t * tree)
510.{
511. if (!(tree->root))
512. return NULL;
513. /* Return the leftmost leaf in the tree */
514. return rbnode_minimum(tree->root);
515.}
516./* Get the tree maximum */
517.red_black_node_t * rbtree_maximum(red_black_tree_t * tree)
518.{
519. if (!(tree->root))
520. return NULL;
521. /* Return the rightmost leaf in the tree */
522. return rbnode_maximum(tree->root);
523.}
524./* Return a pointer to the node containing the given object */
525.red_black_node_t * rbtree_find(red_black_tree_t * tree, void * object)
526.{
527. red_black_node_t * cur_node = tree->root;
528. int comp_result;
529. while (cur_node) {
530. /* In case of equality, we can return the current node. */
531. if ((comp_result = (*(tree->comp))(object, cur_node->object)) == 0)
532. return cur_node;
533. /* Go down to the left or right child. */
534. cur_node = (comp_result > 0) ? cur_node->left : cur_node->right;
535. }
536. /* If we reached here, the object is not found in the tree */
537. return NULL;
538.}
539./* Left-rotate the sub-tree spanned by the given node:
540. *
541. * | RoateRight(y) |
542. * y --------------> x
543. * / \ / \ .
544. * x T3 RoatateLeft(x) T1 y .
545. * / \ <-------------- / \ .
546. * T1 T2 T2 T3
547. */
548.void rbtree_rotate_left(red_black_tree_t * tree, red_black_node_t * x_node)
549.{
550. /* Get the right child of the node */
551. red_black_node_t * y_node = x_node->right;
552. /* Change its left subtree (T2) to x's right subtree */
553. x_node->right = y_node->left;
554. /* Link T2 to its new parent x */
555. if (y_node->left != NULL)
556. y_node->left->parent = x_node;
557. /* Assign x's parent to be y's parent */
558. y_node->parent = x_node->parent;
559. if (!(x_node->parent)) {
560. /* Make y the new tree root */
561. tree->root = y_node;
562. } else {
563. /* Assign a pointer to y from x's parent */
564. if (x_node == x_node->parent->left) {
565. x_node->parent->left = y_node;
566. } else {
567. x_node->parent->right = y_node;
568. }
569. }
570. /* Assign x to be y's left child */
571. y_node->left = x_node;
572. x_node->parent = y_node;
573.}
574./* Right-rotate the sub-tree spanned by the given node */
575.void rbtree_rotate_right(red_black_tree_t * tree, red_black_node_t * y_node)
576.{
577. /* Get the left child of the node */
578. red_black_node_t * x_node = y_node->left;
579. /* Change its right subtree (T2) to y's left subtree */
580. y_node->left = x_node->right;
581. /* Link T2 to its new parent y */
582. if (x_node->right != NULL)
583. x_node->right->parent = y_node;
584. /* Assign y's parent to be x's parent */
585. x_node->parent = y_node->parent;
586. if (!(y_node->parent)) {
587. /* Make x the new tree root */
588. tree->root = x_node;
589. } else {
590. /* Assign a pointer to x from y's parent */
591. if (y_node == y_node->parent->left) {
592. y_node->parent->left = x_node;
593. } else {
594. y_node->parent->right = x_node;
595. }
596. }
597. /* Assign y to be x's right child */
598. x_node->right = y_node;
599. y_node->parent = x_node;
600.}
601./* Fix-up the tree so it maintains the red-black properties after insertion */
602.void rbtree_insert_fixup(red_black_tree_t * tree, red_black_node_t * node)
603.{
604. /* Fix the red-black propreties: we may have inserted a red leaf as the
605. * child of a red parent - so we have to fix the coloring of the parent
606. * recursively.
607. */
608. red_black_node_t * curr_node = node;
609. red_black_node_t * grandparent;
610. red_black_node_t *uncle;
611. assert(node && node->color == rbcRed);
612.
613. while (curr_node != tree->root && curr_node->parent->color == rbcRed) {
614. /* Get a pointer to the current node's grandparent (notice the root is
615. * always black, so the red parent must have a parent).
616. */
617. grandparent = curr_node->parent->parent;
618.
619. if (curr_node->parent == grandparent->left) {
620. /* If the red parent is a left child, the uncle is the right child of
621. * the grandparent.
622. */
623. uncle = grandparent->right;
624. if (uncle && uncle->color == rbcRed) {
625. /* If both parent and uncle are red, color them black and color the
626. * grandparent red.
627. * In case of a NULL uncle, we treat it as a black node.
628. */
629. curr_node->parent->color = rbcBlack;
630. uncle->color = rbcBlack;
631. grandparent->color = rbcRed;
632. /* Move to the grandparent */
633. curr_node = grandparent;
634. } else {
635. /* Make sure the current node is a right child. If not, left-rotate
636. * the parent's sub-tree so the parent becomes the right child of the
637. * current node (see _rotate_left).
638. */
639. if (curr_node == curr_node->parent->right) {
640. curr_node = curr_node->parent;
641. rbtree_rotate_left(tree, curr_node);
642. }
643. /* Color the parent black and the grandparent red */
644. curr_node->parent->color = rbcBlack;
645. grandparent->color = rbcRed;
646. /* Right-rotate the grandparent's sub-tree */
647. rbtree_rotate_right(tree, grandparent);
648. }
649. } else {
650. /* If the red parent is a right child, the uncle is the left child of
651. * the grandparent.
652. */
653. uncle = grandparent->left;
654. if (uncle && uncle->color == rbcRed) {
655. /* If both parent and uncle are red, color them black and color the
656. * grandparent red.
657. * In case of a NULL uncle, we treat it as a black node.
658. */
659. curr_node->parent->color = rbcBlack;
660. uncle->color = rbcBlack;
661. grandparent->color = rbcRed;
662. /* Move to the grandparent */
663. curr_node = grandparent;
664. } else {
665. /* Make sure the current node is a left child. If not, right-rotate
666. * the parent's sub-tree so the parent becomes the left child of the
667. * current node.
668. */
669. if (curr_node == curr_node->parent->left) {
670. curr_node = curr_node->parent;
671. rbtree_rotate_right(tree, curr_node);
672. }
673. /* Color the parent black and the grandparent red */
674. curr_node->parent->color = rbcBlack;
675. grandparent->color = rbcRed;
676. /* Left-rotate the grandparent's sub-tree */
677. rbtree_rotate_left(tree, grandparent);
678. }
679. }
680. }
681. /* Make sure that the root is black */
682. tree->root->color = rbcBlack;
683.}
684.void rbtree_remove_fixup(red_black_tree_t * tree, red_black_node_t * node)
685.{
686. red_black_node_t * curr_node = node;
687. red_black_node_t * sibling;
688. while (curr_node != tree->root && curr_node->color == rbcBlack) {
689. /* Get a pointer to the current node's sibling (notice that the node's
690. * parent must exist, since the node is not the root).
691. */
692. if (curr_node == curr_node->parent->left) {
693. /* If the current node is a left child, its sibling is the right
694. * child of the parent.
695. */
696. sibling = curr_node->parent->right;
697.
698. /* Check the sibling's color. Notice that NULL nodes are treated
699. * as if they are colored black.
700. */
701. if (sibling && sibling->color == rbcRed) {
702. /* In case the sibling is red, color it black and rotate.
703. * Then color the parent red (and the grandparent is now black).
704. */
705. sibling->color = rbcBlack;
706. curr_node->parent->color = rbcRed;
707. rbtree_rotate_left(tree, curr_node->parent);
708. sibling = curr_node->parent->right;
709. }
710.
711. if (sibling &&
712. (!(sibling->left) || sibling->left->color == rbcBlack) &&
713. (!(sibling->right) || sibling->right->color == rbcBlack))
714. {
715. /* If the sibling has two black children, color it red */
716. sibling->color = rbcRed;
717. if (curr_node->parent->color == rbcRed) {
718. /* If the parent is red, we can safely color it black and terminate
719. * the fix-up process.
720. */
721. curr_node->parent->color = rbcBlack;
722. curr_node = tree->root; /* In order to stop the while loop */
723. } else {
724. /* The black depth of the entire sub-tree rooted at the parent is
725. * now too small - fix it up recursively.
726. */
727. curr_node = curr_node->parent;
728. }
729. } else {
730. if (!sibling) {
731. /* Take special care of the case of a NULL sibling */
732. if (curr_node->parent->color == rbcRed) {
733. curr_node->parent->color = rbcBlack;
734. curr_node = tree->root; /* In order to stop the while loop */
735. } else {
736. curr_node = curr_node->parent;
737. }
738. } else {
739. /* In this case, at least one of the sibling's children is red.
740. * It is therfore obvious that the sibling itself is black.
741. */
742. if (sibling->right && sibling->right->color == rbcRed) {
743. /* If the right child of the sibling is red, color it black and
744. * rotate around the current parent.
745. */
746. sibling->right->color = rbcBlack;
747. rbtree_rotate_left(tree, curr_node->parent);
748. } else {
749. /* If the left child of the sibling is red, rotate around the
750. * sibling, then rotate around the new sibling of our current
751. * node.
752. */
753. rbtree_rotate_right(tree, sibling);
754. sibling = curr_node->parent->right;
755. rbtree_rotate_left(tree, sibling);
756. }
757. /* It is now safe to color the parent black and to terminate the
758. * fix-up process.
759. */
760. if (curr_node->parent->parent)
761. curr_node->parent->parent->color = curr_node->parent->color;
762. curr_node->parent->color = rbcBlack;
763. curr_node = tree->root; /* In order to stop the while loop */
764. }
765. }
766. } else {
767. /* If the current node is a right child, its sibling is the left
768. * child of the parent.
769. */
770. sibling = curr_node->parent->left;
771. /* Check the sibling's color. Notice that NULL nodes are treated
772. * as if they are colored black.
773. */
774. if (sibling && sibling->color == rbcRed) {
775. /* In case the sibling is red, color it black and rotate.
776. * Then color the parent red (and the grandparent is now black).
777. */
778. sibling->color = rbcBlack;
779. curr_node->parent->color = rbcRed;
780. rbtree_rotate_right(tree, curr_node->parent);
781. sibling = curr_node->parent->left;
782. }
783. if (sibling &&
784. (!(sibling->left) || sibling->left->color == rbcBlack) &&
785. (!(sibling->right) || sibling->right->color == rbcBlack))
786. {
787. /* If the sibling has two black children, color it red */
788. sibling->color = rbcRed;
789. if (curr_node->parent->color == rbcRed) {
790. /* If the parent is red, we can safely color it black and terminate
791. * the fix-up process.
792. */
793. curr_node->parent->color = rbcBlack;
794. curr_node = tree->root; /* In order to stop the while loop */
795. } else {
796. /* The black depth of the entire sub-tree rooted at the parent is
797. * now too small - fix it up recursively.
798. */
799. curr_node = curr_node->parent;
800. }
801. } else {
802. if (!sibling) {
803. /* Take special care of the case of a NULL sibling */
804. if (curr_node->parent->color == rbcRed) {
805. curr_node->parent->color = rbcBlack;
806. curr_node = tree->root; /* In order to stop the while loop */
807. } else {
808. curr_node = curr_node->parent;
809. }
810. } else {
811. /* In this case, at least one of the sibling's children is red.
812. * It is therfore obvious that the sibling itself is black.
813. */
814. if (sibling->left && sibling->left->color == rbcRed) {
815. /* If the left child of the sibling is red, color it black and
816. * rotate around the current parent
817. */
818. sibling->left->color = rbcBlack;
819. rbtree_rotate_right(tree, curr_node->parent);
820. } else {
821. /* If the right child of the sibling is red, rotate around the
822. * sibling, then rotate around the new sibling of our current
823. * node
824. */
825. rbtree_rotate_left(tree, sibling);
826. sibling = curr_node->parent->left;
827. rbtree_rotate_right(tree, sibling);
828. }
829. /* It is now safe to color the parent black and to terminate the
830. * fix-up process.
831. */
832. if (curr_node->parent->parent)
833. curr_node->parent->parent->color = curr_node->parent->color;
834. curr_node->parent->color = rbcBlack;
835. curr_node = tree->root; /* In order to stop the while loop */
836. }
837. }
838. }
839. }
840. /* The root can always be colored black */
841. curr_node->color = rbcBlack;
842.}
843./* Traverse a red-black tree */
844.void rbtree_traverse(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param)
845.{
846. rbnode_traverse(tree->root, op, param);
847.}
848./* Right-first traverse a red-black tree */
849.void rbtree_traverse_right(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param)
850.{
851. rbnode_traverse_right(tree->root, op, param);
852.}
/******************************************************************************
* red_black_tree.c *
* Download From: *
* http://www.cs.tau.ac.il/~efif/courses/Software1_Summer_03/code/rbtree/ *
* Last Edited by: cheungmine *
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "red_black_tree.h"
/*!
* Operations on red_black_node_t struct
*/
/* Construct a red-black tree node */
red_black_node_t * rbnode_construct(void * object, red_black_color_enum color)
{
red_black_node_t * node = (red_black_node_t *) malloc(sizeof(red_black_node_t));
if (!node) {
fprintf(stderr, "Not enough memory!\n");
return NULL;
}
node->object = object;
node->color = color;
node->parent = node->right = node->left = NULL;
return node;
}
/* Destructor of a red-black tree node */
void rbnode_destruct(red_black_node_t * node)
{
if (!node) return;
rbnode_destruct(node->right);
rbnode_destruct(node->left);
free(node);
}
/* Calculate the depth of the subtree spanned by a given node */
int rbnode_depth(red_black_node_t * node)
{
/* Recursively calculate the depth of the left and right sub-trees */
int iRightDepth = (node->right) ? rbnode_depth(node->right) : 0;
int iLeftDepth = (node->left) ? rbnode_depth(node->left) : 0;
/* Return the maximal child depth + 1 (the current node) */
return ((iRightDepth > iLeftDepth) ? (iRightDepth + 1) : (iLeftDepth + 1));
}
/* Return the leftmost leaf in the tree */
red_black_node_t * rbnode_minimum(red_black_node_t * node)
{
while (node->left)
node = node->left;
return node;
}
/* Return the rightmost leaf in the tree */
red_black_node_t * rbnode_maximum(red_black_node_t * node)
{
while (node->right)
node = node->right;
return node;
}
/* Replace the object */
void rbnode_replace(red_black_node_t * node, void * object)
{
/* Make sure the replacement does not violate the tree order */
/* Replace the object at node */
node->object = object;
}
/* Get the next node in the tree (according to the tree order) */
red_black_node_t * rbnode_successor(red_black_node_t * node)
{
red_black_node_t * succ_node;
if (node->right) {
/* If there is a right child, the successor is the minimal object in
* the sub-tree spanned by this child.
*/
succ_node = node->right;
while (succ_node->left)
succ_node = succ_node->left;
}
else {
/* Otherwise, go up the tree until reaching the parent from the left
* direction.
*/
red_black_node_t * prev_node = node;
succ_node = node->parent;
while (succ_node && prev_node == succ_node->right) {
prev_node = succ_node;
succ_node = succ_node->parent;
}
}
return (succ_node);
}
/* Get the previous node in the tree (according to the tree order) */
red_black_node_t * rbnode_predecessor(red_black_node_t * node)
{
red_black_node_t * pred_node;
if (node->left) {
/* If there is a left child, the predecessor is the maximal object in
* the sub-tree spanned by this child.
*/
pred_node = node->left;
while (pred_node->right)
pred_node = pred_node->right;
} else {
/* Otherwise, go up the tree until reaching the parent from the right
* direction.
*/
red_black_node_t * prev_node = node;
pred_node = node->parent;
while (pred_node && prev_node == pred_node->left) {
prev_node = pred_node;
pred_node = pred_node->parent;
}
}
return (pred_node);
}
/* Return a pointer to a duplication of the given node */
red_black_node_t * rbnode_duplicate(red_black_node_t * node)
{
/* Create a node of the same color, containing the same object */
red_black_node_t * dup_node = rbnode_construct(node->object, node->color);
if (!dup_node) return NULL;
/* Duplicate the children recursively */
if (node->right) {
dup_node->right = rbnode_duplicate (node->right);
dup_node->right->parent = dup_node;
} else {
dup_node->right = NULL;
}
if (node->left) {
dup_node->left = rbnode_duplicate(node->left);
dup_node->left->parent = dup_node;
} else {
dup_node->left = NULL;
}
return dup_node; /* Return the duplicated node */
}
/* Traverse a red-black subtree */
void rbnode_traverse(red_black_node_t * node, pfcbRBTreeOperFunc * opFunc, void* param)
{
if (!node) return;
rbnode_traverse(node->left, opFunc, param);
opFunc(node->object, param);
rbnode_traverse(node->right, opFunc, param);
}
/* Right-first traverse a red-black subtree */
void rbnode_traverse_right(red_black_node_t * node, pfcbRBTreeOperFunc * opFunc, void* param)
{
if (!node) return;
rbnode_traverse_right(node->right, opFunc, param);
opFunc(node->object, param);
rbnode_traverse_right(node->left, opFunc, param);
}
/*
* Operations on red_black_tree_t struct
*/
/* Intialize a tree */
void rbtree_init(red_black_tree_t * tree, pfcbRBTreeCompFunc * comp)
{
tree->comp = comp;
tree->iSize = 0;
tree->root = NULL;
}
/* Construct a tree given a comparison function */
red_black_tree_t * rbtree_construct(pfcbRBTreeCompFunc * comp)
{
red_black_tree_t * tree = (red_black_tree_t *) malloc(sizeof(red_black_tree_t));
if (!tree) {
fprintf(stderr, "Not enough memory!\n");
return NULL;
}
rbtree_init(tree, comp);
return tree;
}
/* Remove all objects from a black-red tree */
void rbtree_clean(red_black_tree_t * tree)
{
if (tree->root)
rbnode_destruct(tree->root);
tree->root = NULL;
tree->iSize = 0;
}
/* Destruct a red-black tree */
void rbtree_destruct(red_black_tree_t * tree)
{
rbtree_clean(tree);
free(tree);
}
/* Returns the size of the tree */
int rbtree_size(red_black_tree_t * tree)
{
return tree->iSize;
}
/* Returns the depth of the tree */
int rbtree_depth(red_black_tree_t * tree)
{
if (!(tree->root))
return 0;
return rbnode_depth(tree->root);
}
/* Check whether the tree contains an object */
int rbtree_contains(red_black_tree_t * tree, void * object)
{
return (rbtree_find(tree, object) != NULL);
}
/* Insert an object to the tree */
red_black_node_t * rbtree_insert(red_black_tree_t * tree, void * object)
{
int cmp;
red_black_node_t * cur_node;
red_black_node_t * new_node = NULL;
if (!(tree->root)) {
/* Assign a new root node. Notice that the root is always black */
new_node = rbnode_construct(object, rbcBlack);
if (!new_node) return NULL;
tree->root = new_node;
tree->iSize = 1;
return new_node;
}
/* Find a place for the new object, and insert it as a red leaf */
cur_node = tree->root;
while (cur_node) {
cmp = (*(tree->comp))(object, cur_node->object);
#ifdef RBTREE_SUPPORTS_MULTI_OBJECTS
if (cmp==0) {
if (cur_node->object != object)
((rbtree_object_base*)cur_node->object)->__next_object = (rbtree_object_base*)object;
return cur_node;
}
#endif
/* Compare inserted object with the object stored in the current node */
if (cmp > 0) {
if (!(cur_node->left)) {
/* Insert the new leaf as the left child of the current node */
new_node = rbnode_construct(object, rbcRed);
if (!new_node) return NULL;
cur_node->left = new_node;
new_node->parent = cur_node;
cur_node = NULL; /* terminate the while loop */
} else {
cur_node = cur_node->left; /* Go to the left sub-tree */
}
} else {
if (!(cur_node->right)) {
/* Insert the new leaf as the right child of the current node */
new_node = rbnode_construct(object, rbcRed);
if (!new_node) return NULL;
cur_node->right = new_node;
new_node->parent = cur_node;
cur_node = NULL; /* terminate the while loop */
} else {
cur_node = cur_node->right; /* Go to the right sub-tree */
}
}
}
/* Mark that a new node was added */
tree->iSize++;
/* Fix up the tree properties */
rbtree_insert_fixup(tree, new_node);
return new_node;
}
/* Insert an unique object to the tree */
red_black_node_t * rbtree_insert_unique(red_black_tree_t * tree, void * object)
{
int cmp;
red_black_node_t * cur_node;
red_black_node_t * new_node = NULL;
if (!(tree->root)) {
/* Assign a new root node. Notice that the root is always black */
new_node = rbnode_construct(object, rbcBlack);
if (!new_node) return NULL;
tree->root = new_node;
tree->iSize = 1;
return new_node;
}
/* Find a place for the new object, and insert it as a red leaf */
cur_node = tree->root;
while (cur_node) {
cmp = (*(tree->comp))(object, cur_node->object);
if (cmp==0) {
/* there already has an object with the same id as object to be inserted */
return cur_node;
}
/* Compare inserted object with the object stored in the current node */
if (cmp > 0) {
if (!(cur_node->left)) {
/* Insert the new leaf as the left child of the current node */
new_node = rbnode_construct(object, rbcRed);
if (!new_node)
return NULL;
cur_node->left = new_node;
new_node->parent = cur_node;
cur_node = NULL; /* terminate the while loop */
} else {
cur_node = cur_node->left; /* Go to the left sub-tree */
}
} else {
if (!(cur_node->right)) {
/* Insert the new leaf as the right child of the current node */
new_node = rbnode_construct(object, rbcRed);
if (!new_node)
return NULL;
cur_node->right = new_node;
new_node->parent = cur_node;
cur_node = NULL; /* terminate the while loop */
} else {
cur_node = cur_node->right; /* Go to the right sub-tree */
}
}
}
/* Mark that a new node was added */
tree->iSize++;
/* Fix up the tree properties */
rbtree_insert_fixup(tree, new_node);
return new_node;
}
/* Insert a new object to the tree as the a successor of a given node */
red_black_node_t * insert_successor_at(red_black_tree_t * tree,
red_black_node_t * at_node, void * object)
{
red_black_node_t * parent;
red_black_node_t * new_node;
if (!(tree->root)) {
/* Assign a new root node. Notice that the root is always black */
new_node = rbnode_construct(object, rbcBlack);
if (!new_node) return NULL;
tree->root = new_node;
tree->iSize = 1;
return new_node;
}
/* Insert the new object as a red leaf, being the successor of node */
new_node = rbnode_construct(object, rbcRed);
if (!new_node) return NULL;
if (!at_node) {
/* The new node should become the tree minimum: Place is as the left
* child of the current minimal leaf.
*/
parent = rbnode_minimum(tree->root);
parent->left = new_node;
} else {
/* Make sure the insertion does not violate the tree order */
/* In case given node has no right child, place the new node as its
* right child. Otherwise, place it at the leftmost position at the
* sub-tree rooted at its right side.
*/
if (!at_node->right) {
parent = at_node;
parent->right = new_node;
} else {
parent = rbnode_minimum(at_node->right);
parent->left = new_node;
}
}
new_node->parent = parent;
/* Mark that a new node was added */
tree->iSize++;
/* Fix up the tree properties */
rbtree_insert_fixup(tree, new_node);
return new_node;
}
/* Insert a new object to the tree as the a predecessor of a given node */
red_black_node_t * insert_predecessor_at(red_black_tree_t * tree,
red_black_node_t * at_node, void * object)
{
red_black_node_t * parent;
red_black_node_t * new_node;
if (!(tree->root)) {
/* Assign a new root node. Notice that the root is always black */
new_node = rbnode_construct(object, rbcBlack);
if (!new_node) return NULL;
tree->root = new_node;
tree->iSize = 1;
return new_node;
}
/* Insert the new object as a red leaf, being the predecessor of at_node */
new_node = rbnode_construct(object, rbcRed);
if (!new_node) return NULL;
if (!at_node) {
/* The new node should become the tree maximum: Place is as the right
* child of the current maximal leaf.
*/
parent = rbnode_maximum(tree->root);
parent->right = new_node;
} else {
/* Make sure the insertion does not violate the tree order */
/* In case given node has no left child, place the new node as its
* left child. Otherwise, place it at the rightmost position at the
* sub-tree rooted at its left side.
*/
if (!(at_node->left)) {
parent = at_node;
parent->left = new_node;
} else {
parent = rbnode_maximum (at_node->left);
parent->right = new_node;
}
}
new_node->parent = parent;
/* Mark that a new node was added */
tree->iSize++;
/* Fix up the tree properties */
rbtree_insert_fixup(tree, new_node);
return new_node;
}
/* Remove an object from the tree */
void rbtree_remove(red_black_tree_t * tree, void * object)
{
red_black_node_t * node = rbtree_find(tree, object); /* find the node */
rbtree_remove_at(tree, node); /* remove the node */
}
/* Remove the object pointed by the given node. */
void rbtree_remove_at(red_black_tree_t * tree, red_black_node_t * node)
{
red_black_node_t * child = NULL;
/* In case of deleting the single object stored in the tree, free the root,
* thus emptying the tree.
*/
if (tree->iSize == 1) {
rbnode_destruct(tree->root);
tree->root = NULL;
tree->iSize = 0;
return;
}
/* Remove the given node from the tree */
if (node->left && node->right) {
/* If the node we want to remove has two children, find its successor,
* which is the leftmost child in its right sub-tree and has at most
* one child (it may have a right child).
*/
red_black_node_t * succ_node = rbnode_minimum(node->right);
/* Now physically swap node and its successor. Notice this may temporarily
* violate the tree properties, but we are going to remove node anyway.
* This way we have moved node to a position were it is more convinient
* to delete it.
*/
int immediate_succ = (node->right == succ_node);
red_black_node_t * succ_parent = succ_node->parent;
red_black_node_t * succ_left = succ_node->left;
red_black_node_t * succ_right = succ_node->right;
red_black_color_enum succ_color = succ_node->color;
succ_node->parent = node->parent;
succ_node->left = node->left;
succ_node->right = immediate_succ ? node : node->right;
succ_node->color = node->color;
node->parent = immediate_succ ? succ_node : succ_parent;
node->left = succ_left;
node->right = succ_right;
node->color = succ_color;
if (!immediate_succ) {
if (succ_node == node->parent->left)
node->parent->left = node;
else
node->parent->right = node;
}
if (node->left)
node->left->parent = node;
if (node->right)
node->right->parent = node;
if (succ_node->parent) {
if (node == succ_node->parent->left)
succ_node->parent->left = succ_node;
else
succ_node->parent->right = succ_node;
} else {
tree->root = succ_node;
}
if (succ_node->left)
succ_node->left->parent = succ_node;
if (succ_node->right)
succ_node->right->parent = succ_node;
}
/* At this stage, the node we are going to remove has at most one child */
child = (node->left) ? node->left : node->right;
/* Splice out the node to be removed, by linking its parent straight to the
* removed node's single child.
*/
if (child)
child->parent = node->parent;
if (!(node->parent)) {
/* If we are deleting the root, make the child the new tree node */
tree->root = child;
} else {
/* Link the removed node parent to its child */
if (node == node->parent->left) {
node->parent->left = child;
} else {
node->parent->right = child;
}
}
/* Fix-up the red-black properties that may have been damaged: If we have
* just removed a black node, the black-depth property is no longer valid.
*/
if (node->color == rbcBlack && child)
rbtree_remove_fixup(tree, child);
/* Delete the un-necessary node (we nullify both its children because the
* node's destructor is recursive).
*/
node->left = NULL;
node->right = NULL;
free(node);
/* Descrease the number of objects in the tree */
tree->iSize--;
}
/* Get the tree minimum */
red_black_node_t * rbtree_minimum(red_black_tree_t * tree)
{
if (!(tree->root))
return NULL;
/* Return the leftmost leaf in the tree */
return rbnode_minimum(tree->root);
}
/* Get the tree maximum */
red_black_node_t * rbtree_maximum(red_black_tree_t * tree)
{
if (!(tree->root))
return NULL;
/* Return the rightmost leaf in the tree */
return rbnode_maximum(tree->root);
}
/* Return a pointer to the node containing the given object */
red_black_node_t * rbtree_find(red_black_tree_t * tree, void * object)
{
red_black_node_t * cur_node = tree->root;
int comp_result;
while (cur_node) {
/* In case of equality, we can return the current node. */
if ((comp_result = (*(tree->comp))(object, cur_node->object)) == 0)
return cur_node;
/* Go down to the left or right child. */
cur_node = (comp_result > 0) ? cur_node->left : cur_node->right;
}
/* If we reached here, the object is not found in the tree */
return NULL;
}
/* Left-rotate the sub-tree spanned by the given node:
*
* | RoateRight(y) |
* y --------------> x
* / \ / \ .
* x T3 RoatateLeft(x) T1 y .
* / \ <-------------- / \ .
* T1 T2 T2 T3
*/
void rbtree_rotate_left(red_black_tree_t * tree, red_black_node_t * x_node)
{
/* Get the right child of the node */
red_black_node_t * y_node = x_node->right;
/* Change its left subtree (T2) to x's right subtree */
x_node->right = y_node->left;
/* Link T2 to its new parent x */
if (y_node->left != NULL)
y_node->left->parent = x_node;
/* Assign x's parent to be y's parent */
y_node->parent = x_node->parent;
if (!(x_node->parent)) {
/* Make y the new tree root */
tree->root = y_node;
} else {
/* Assign a pointer to y from x's parent */
if (x_node == x_node->parent->left) {
x_node->parent->left = y_node;
} else {
x_node->parent->right = y_node;
}
}
/* Assign x to be y's left child */
y_node->left = x_node;
x_node->parent = y_node;
}
/* Right-rotate the sub-tree spanned by the given node */
void rbtree_rotate_right(red_black_tree_t * tree, red_black_node_t * y_node)
{
/* Get the left child of the node */
red_black_node_t * x_node = y_node->left;
/* Change its right subtree (T2) to y's left subtree */
y_node->left = x_node->right;
/* Link T2 to its new parent y */
if (x_node->right != NULL)
x_node->right->parent = y_node;
/* Assign y's parent to be x's parent */
x_node->parent = y_node->parent;
if (!(y_node->parent)) {
/* Make x the new tree root */
tree->root = x_node;
} else {
/* Assign a pointer to x from y's parent */
if (y_node == y_node->parent->left) {
y_node->parent->left = x_node;
} else {
y_node->parent->right = x_node;
}
}
/* Assign y to be x's right child */
x_node->right = y_node;
y_node->parent = x_node;
}
/* Fix-up the tree so it maintains the red-black properties after insertion */
void rbtree_insert_fixup(red_black_tree_t * tree, red_black_node_t * node)
{
/* Fix the red-black propreties: we may have inserted a red leaf as the
* child of a red parent - so we have to fix the coloring of the parent
* recursively.
*/
red_black_node_t * curr_node = node;
red_black_node_t * grandparent;
red_black_node_t *uncle;
assert(node && node->color == rbcRed);
while (curr_node != tree->root && curr_node->parent->color == rbcRed) {
/* Get a pointer to the current node's grandparent (notice the root is
* always black, so the red parent must have a parent).
*/
grandparent = curr_node->parent->parent;
if (curr_node->parent == grandparent->left) {
/* If the red parent is a left child, the uncle is the right child of
* the grandparent.
*/
uncle = grandparent->right;
if (uncle && uncle->color == rbcRed) {
/* If both parent and uncle are red, color them black and color the
* grandparent red.
* In case of a NULL uncle, we treat it as a black node.
*/
curr_node->parent->color = rbcBlack;
uncle->color = rbcBlack;
grandparent->color = rbcRed;
/* Move to the grandparent */
curr_node = grandparent;
} else {
/* Make sure the current node is a right child. If not, left-rotate
* the parent's sub-tree so the parent becomes the right child of the
* current node (see _rotate_left).
*/
if (curr_node == curr_node->parent->right) {
curr_node = curr_node->parent;
rbtree_rotate_left(tree, curr_node);
}
/* Color the parent black and the grandparent red */
curr_node->parent->color = rbcBlack;
grandparent->color = rbcRed;
/* Right-rotate the grandparent's sub-tree */
rbtree_rotate_right(tree, grandparent);
}
} else {
/* If the red parent is a right child, the uncle is the left child of
* the grandparent.
*/
uncle = grandparent->left;
if (uncle && uncle->color == rbcRed) {
/* If both parent and uncle are red, color them black and color the
* grandparent red.
* In case of a NULL uncle, we treat it as a black node.
*/
curr_node->parent->color = rbcBlack;
uncle->color = rbcBlack;
grandparent->color = rbcRed;
/* Move to the grandparent */
curr_node = grandparent;
} else {
/* Make sure the current node is a left child. If not, right-rotate
* the parent's sub-tree so the parent becomes the left child of the
* current node.
*/
if (curr_node == curr_node->parent->left) {
curr_node = curr_node->parent;
rbtree_rotate_right(tree, curr_node);
}
/* Color the parent black and the grandparent red */
curr_node->parent->color = rbcBlack;
grandparent->color = rbcRed;
/* Left-rotate the grandparent's sub-tree */
rbtree_rotate_left(tree, grandparent);
}
}
}
/* Make sure that the root is black */
tree->root->color = rbcBlack;
}
void rbtree_remove_fixup(red_black_tree_t * tree, red_black_node_t * node)
{
red_black_node_t * curr_node = node;
red_black_node_t * sibling;
while (curr_node != tree->root && curr_node->color == rbcBlack) {
/* Get a pointer to the current node's sibling (notice that the node's
* parent must exist, since the node is not the root).
*/
if (curr_node == curr_node->parent->left) {
/* If the current node is a left child, its sibling is the right
* child of the parent.
*/
sibling = curr_node->parent->right;
/* Check the sibling's color. Notice that NULL nodes are treated
* as if they are colored black.
*/
if (sibling && sibling->color == rbcRed) {
/* In case the sibling is red, color it black and rotate.
* Then color the parent red (and the grandparent is now black).
*/
sibling->color = rbcBlack;
curr_node->parent->color = rbcRed;
rbtree_rotate_left(tree, curr_node->parent);
sibling = curr_node->parent->right;
}
if (sibling &&
(!(sibling->left) || sibling->left->color == rbcBlack) &&
(!(sibling->right) || sibling->right->color == rbcBlack))
{
/* If the sibling has two black children, color it red */
sibling->color = rbcRed;
if (curr_node->parent->color == rbcRed) {
/* If the parent is red, we can safely color it black and terminate
* the fix-up process.
*/
curr_node->parent->color = rbcBlack;
curr_node = tree->root; /* In order to stop the while loop */
} else {
/* The black depth of the entire sub-tree rooted at the parent is
* now too small - fix it up recursively.
*/
curr_node = curr_node->parent;
}
} else {
if (!sibling) {
/* Take special care of the case of a NULL sibling */
if (curr_node->parent->color == rbcRed) {
curr_node->parent->color = rbcBlack;
curr_node = tree->root; /* In order to stop the while loop */
} else {
curr_node = curr_node->parent;
}
} else {
/* In this case, at least one of the sibling's children is red.
* It is therfore obvious that the sibling itself is black.
*/
if (sibling->right && sibling->right->color == rbcRed) {
/* If the right child of the sibling is red, color it black and
* rotate around the current parent.
*/
sibling->right->color = rbcBlack;
rbtree_rotate_left(tree, curr_node->parent);
} else {
/* If the left child of the sibling is red, rotate around the
* sibling, then rotate around the new sibling of our current
* node.
*/
rbtree_rotate_right(tree, sibling);
sibling = curr_node->parent->right;
rbtree_rotate_left(tree, sibling);
}
/* It is now safe to color the parent black and to terminate the
* fix-up process.
*/
if (curr_node->parent->parent)
curr_node->parent->parent->color = curr_node->parent->color;
curr_node->parent->color = rbcBlack;
curr_node = tree->root; /* In order to stop the while loop */
}
}
} else {
/* If the current node is a right child, its sibling is the left
* child of the parent.
*/
sibling = curr_node->parent->left;
/* Check the sibling's color. Notice that NULL nodes are treated
* as if they are colored black.
*/
if (sibling && sibling->color == rbcRed) {
/* In case the sibling is red, color it black and rotate.
* Then color the parent red (and the grandparent is now black).
*/
sibling->color = rbcBlack;
curr_node->parent->color = rbcRed;
rbtree_rotate_right(tree, curr_node->parent);
sibling = curr_node->parent->left;
}
if (sibling &&
(!(sibling->left) || sibling->left->color == rbcBlack) &&
(!(sibling->right) || sibling->right->color == rbcBlack))
{
/* If the sibling has two black children, color it red */
sibling->color = rbcRed;
if (curr_node->parent->color == rbcRed) {
/* If the parent is red, we can safely color it black and terminate
* the fix-up process.
*/
curr_node->parent->color = rbcBlack;
curr_node = tree->root; /* In order to stop the while loop */
} else {
/* The black depth of the entire sub-tree rooted at the parent is
* now too small - fix it up recursively.
*/
curr_node = curr_node->parent;
}
} else {
if (!sibling) {
/* Take special care of the case of a NULL sibling */
if (curr_node->parent->color == rbcRed) {
curr_node->parent->color = rbcBlack;
curr_node = tree->root; /* In order to stop the while loop */
} else {
curr_node = curr_node->parent;
}
} else {
/* In this case, at least one of the sibling's children is red.
* It is therfore obvious that the sibling itself is black.
*/
if (sibling->left && sibling->left->color == rbcRed) {
/* If the left child of the sibling is red, color it black and
* rotate around the current parent
*/
sibling->left->color = rbcBlack;
rbtree_rotate_right(tree, curr_node->parent);
} else {
/* If the right child of the sibling is red, rotate around the
* sibling, then rotate around the new sibling of our current
* node
*/
rbtree_rotate_left(tree, sibling);
sibling = curr_node->parent->left;
rbtree_rotate_right(tree, sibling);
}
/* It is now safe to color the parent black and to terminate the
* fix-up process.
*/
if (curr_node->parent->parent)
curr_node->parent->parent->color = curr_node->parent->color;
curr_node->parent->color = rbcBlack;
curr_node = tree->root; /* In order to stop the while loop */
}
}
}
}
/* The root can always be colored black */
curr_node->color = rbcBlack;
}
/* Traverse a red-black tree */
void rbtree_traverse(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param)
{
rbnode_traverse(tree->root, op, param);
}
/* Right-first traverse a red-black tree */
void rbtree_traverse_right(red_black_tree_t * tree, pfcbRBTreeOperFunc * op, void *param)
{
rbnode_traverse_right(tree->root, op, param);
}
view plaincopy to clipboardprint?
//
// rbtree_test.c
// by cheungmine
//
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// RBTREE_SUPPORTS_MULTI_OBJECTS 在下面的文件中被定义,如果不想支持多图,注释掉它
#include "red_black_tree.h"
/*!
*/
int cmp_int(int a, int b)
{
return (a > b) ? -1 : ((a == b) ? 0 : 1);
}
/*!
*/
void my_print(int value)
{
printf("%d ", value);
}
#if !defined(RBTREE_SUPPORTS_MULTI_OBJECTS)
void test_rbtree_insert_repeat()
{
int i, n;
red_black_tree_t tree;
red_black_node_t *node, *node2;
n = 20;
rbtree_init(&tree, (pfcbRBTreeCompFunc*) cmp_int);
for (i=0; i<n; i++){
rbtree_insert(&tree, (void*) i);
}
node = rbtree_find(&tree, (void*) 5);
assert(node);
node2 = rbtree_insert(&tree, (void*) 5);
assert(node2);
assert(node!=node2);
node = rbtree_find(&tree, (void*) 10);
assert(node);
node2 = rbtree_insert(&tree, (void*) 10);
assert(node2);
assert(node!=node2);
printf("n = %d, d = %d\n", n, rbtree_depth(&tree));
rbtree_traverse(&tree, (pfcbRBTreeOperFunc*) my_print);
printf("\n");
rbtree_traverse_right(&tree, (pfcbRBTreeOperFunc*) my_print);
printf("\n");
rbtree_clean(&tree);
}
#endif
void test_rbtree_insert_unique()
{
int i, n;
red_black_tree_t tree;
red_black_node_t *node, *node2;
n = 20;
rbtree_init(&tree, (pfcbRBTreeCompFunc*) cmp_int);
for (i=0; i<n; i++){
rbtree_insert_unique(&tree, (void*) i);
}
node = rbtree_find(&tree, (void*) 5);
assert(node);
node2 = rbtree_insert_unique(&tree, (void*) 5);
assert(node2);
assert(node==node2);
node = rbtree_find(&tree, (void*) 10);
assert(node);
node2 = rbtree_insert_unique(&tree, (void*) 10);
assert(node2);
assert(node==node2);
printf("n = %d, d = %d\n", n, rbtree_depth(&tree));
rbtree_traverse(&tree, (pfcbRBTreeOperFunc*) my_print, 0);
printf("\n");
rbtree_traverse_right(&tree, (pfcbRBTreeOperFunc*) my_print, 0);
printf("\n");
rbtree_clean(&tree);
}
#ifdef RBTREE_SUPPORTS_MULTI_OBJECTS
typedef struct _MYOBJECT
{
struct _MYOBJECT *__next_object;
int data;
}MYOBJECT;
int cmp_int_multimap(MYOBJECT *a, MYOBJECT *b)
{
return (a->data > b->data) ? -1 : ((a->data == b->data) ? 0 : 1);
}
/*!
*/
void my_print_multimap(MYOBJECT *obj)
{
while (obj) {
printf("%d ", obj->data);
obj = obj->__next_object;
}
}
void test_rbtree_insert_multimap()
{
int i, n;
MYOBJECT *obj;
MYOBJECT **objects;
red_black_tree_t tree;
red_black_node_t *node;
n = 20;
rbtree_init(&tree, (pfcbRBTreeCompFunc*) cmp_int_multimap);
objects = (MYOBJECT**) calloc(n, sizeof(MYOBJECT*));
for (i=0; i<n; i++){
obj = (MYOBJECT*) malloc(sizeof(MYOBJECT));
objects[i] = obj;
obj->__next_object = 0; // MUST be NULL
obj->data = i;
rbtree_insert(&tree, (void*) obj);
}
rbtree_insert(&tree, (void*) objects[5]);
obj = (MYOBJECT*) malloc(sizeof(MYOBJECT));
obj->__next_object = 0; // MUST be NULL
obj->data = 5;
rbtree_insert(&tree, (void*) obj);
printf("n = %d, d = %d\n", n, rbtree_depth(&tree));
printf("(");
node = rbtree_find(&tree, (void*) objects[5]);
if (node){
MYOBJECT *obj = node->object;
while (obj) {
printf("%d ", obj->data);
obj = obj->__next_object;
}
}
printf(")\n");
rbtree_traverse(&tree, (pfcbRBTreeOperFunc*) my_print_multimap, 0);
printf("\n");
rbtree_traverse_right(&tree, (pfcbRBTreeOperFunc*) my_print_multimap, 0);
printf("\n");
rbtree_clean(&tree);
for (i=0; i<n; i++){
free(objects[i]);
}
free(objects);
free(obj);
}
#endif // RBTREE_SUPPORTS_MULTI_OBJECTS
int main(int argc, char * argv[])
{
#if !defined(RBTREE_SUPPORTS_MULTI_OBJECTS)
test_rbtree_insert_repeat();
#endif
test_rbtree_insert_unique();
test_rbtree_insert_multimap();
return 0;
}
//
// rbtree_test.c
// by cheungmine
//
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
// RBTREE_SUPPORTS_MULTI_OBJECTS 在下面的文件中被定义,如果不想支持多图,注释掉它
#include "red_black_tree.h"
/*!
*/
int cmp_int(int a, int b)
{
return (a > b) ? -1 : ((a == b) ? 0 : 1);
}
/*!
*/
void my_print(int value)
{
printf("%d ", value);
}
#if !defined(RBTREE_SUPPORTS_MULTI_OBJECTS)
void test_rbtree_insert_repeat()
{
int i, n;
red_black_tree_t tree;
red_black_node_t *node, *node2;
n = 20;
rbtree_init(&tree, (pfcbRBTreeCompFunc*) cmp_int);
for (i=0; i<n; i++){
rbtree_insert(&tree, (void*) i);
}
node = rbtree_find(&tree, (void*) 5);
assert(node);
node2 = rbtree_insert(&tree, (void*) 5);
assert(node2);
assert(node!=node2);
node = rbtree_find(&tree, (void*) 10);
assert(node);
node2 = rbtree_insert(&tree, (void*) 10);
assert(node2);
assert(node!=node2);
printf("n = %d, d = %d\n", n, rbtree_depth(&tree));
rbtree_traverse(&tree, (pfcbRBTreeOperFunc*) my_print);
printf("\n");
rbtree_traverse_right(&tree, (pfcbRBTreeOperFunc*) my_print);
printf("\n");
rbtree_clean(&tree);
}
#endif
void test_rbtree_insert_unique()
{
int i, n;
red_black_tree_t tree;
red_black_node_t *node, *node2;
n = 20;
rbtree_init(&tree, (pfcbRBTreeCompFunc*) cmp_int);
for (i=0; i<n; i++){
rbtree_insert_unique(&tree, (void*) i);
}
node = rbtree_find(&tree, (void*) 5);
assert(node);
node2 = rbtree_insert_unique(&tree, (void*) 5);
assert(node2);
assert(node==node2);
node = rbtree_find(&tree, (void*) 10);
assert(node);
node2 = rbtree_insert_unique(&tree, (void*) 10);
assert(node2);
assert(node==node2);
printf("n = %d, d = %d\n", n, rbtree_depth(&tree));
rbtree_traverse(&tree, (pfcbRBTreeOperFunc*) my_print, 0);
printf("\n");
rbtree_traverse_right(&tree, (pfcbRBTreeOperFunc*) my_print, 0);
printf("\n");
rbtree_clean(&tree);
}
#ifdef RBTREE_SUPPORTS_MULTI_OBJECTS
typedef struct _MYOBJECT
{
struct _MYOBJECT *__next_object;
int data;
}MYOBJECT;
int cmp_int_multimap(MYOBJECT *a, MYOBJECT *b)
{
return (a->data > b->data) ? -1 : ((a->data == b->data) ? 0 : 1);
}
/*!
*/
void my_print_multimap(MYOBJECT *obj)
{
while (obj) {
printf("%d ", obj->data);
obj = obj->__next_object;
}
}
void test_rbtree_insert_multimap()
{
int i, n;
MYOBJECT *obj;
MYOBJECT **objects;
red_black_tree_t tree;
red_black_node_t *node;
n = 20;
rbtree_init(&tree, (pfcbRBTreeCompFunc*) cmp_int_multimap);
objects = (MYOBJECT**) calloc(n, sizeof(MYOBJECT*));
for (i=0; i<n; i++){
obj = (MYOBJECT*) malloc(sizeof(MYOBJECT));
objects[i] = obj;
obj->__next_object = 0; // MUST be NULL
obj->data = i;
rbtree_insert(&tree, (void*) obj);
}
rbtree_insert(&tree, (void*) objects[5]);
obj = (MYOBJECT*) malloc(sizeof(MYOBJECT));
obj->__next_object = 0; // MUST be NULL
obj->data = 5;
rbtree_insert(&tree, (void*) obj);
printf("n = %d, d = %d\n", n, rbtree_depth(&tree));
printf("(");
node = rbtree_find(&tree, (void*) objects[5]);
if (node){
MYOBJECT *obj = node->object;
while (obj) {
printf("%d ", obj->data);
obj = obj->__next_object;
}
}
printf(")\n");
rbtree_traverse(&tree, (pfcbRBTreeOperFunc*) my_print_multimap, 0);
printf("\n");
rbtree_traverse_right(&tree, (pfcbRBTreeOperFunc*) my_print_multimap, 0);
printf("\n");
rbtree_clean(&tree);
for (i=0; i<n; i++){
free(objects[i]);
}
free(objects);
free(obj);
}
#endif // RBTREE_SUPPORTS_MULTI_OBJECTS
int main(int argc, char * argv[])
{
#if !defined(RBTREE_SUPPORTS_MULTI_OBJECTS)
test_rbtree_insert_repeat();
#endif
test_rbtree_insert_unique();
test_rbtree_insert_multimap();
return 0;
}