+/*\r
+ Red Black balanced tree library\r
+\r
+ > Created (Julienne Walker): August 23, 2003\r
+ > Modified (Julienne Walker): March 14, 2008\r
+*/\r
+#include "jsw_rbtree.h"\r
+\r
+#ifdef __cplusplus\r
+#include <cstdlib>\r
+\r
+using std::malloc;\r
+using std::free;\r
+using std::size_t;\r
+#else\r
+#include <stdlib.h>\r
+#endif\r
+\r
+#ifndef HEIGHT_LIMIT\r
+#define HEIGHT_LIMIT 64 /* Tallest allowable tree */\r
+#endif\r
+\r
+typedef struct jsw_rbnode {\r
+ int red; /* Color (1=red, 0=black) */\r
+ void *data; /* User-defined content */\r
+ struct jsw_rbnode *link[2]; /* Left (0) and right (1) links */\r
+} jsw_rbnode_t;\r
+\r
+struct jsw_rbtree {\r
+ jsw_rbnode_t *root; /* Top of the tree */\r
+ cmp_f cmp; /* Compare two items */\r
+ dup_f dup; /* Clone an item (user-defined) */\r
+ rel_f rel; /* Destroy an item (user-defined) */\r
+ size_t size; /* Number of items (user-defined) */\r
+};\r
+\r
+struct jsw_rbtrav {\r
+ jsw_rbtree_t *tree; /* Paired tree */\r
+ jsw_rbnode_t *it; /* Current node */\r
+ jsw_rbnode_t *path[HEIGHT_LIMIT]; /* Traversal path */\r
+ size_t top; /* Top of stack */\r
+};\r
+\r
+/**\r
+ <summary>\r
+ Checks the color of a red black node\r
+ <summary>\r
+ <param name="root">The node to check</param>\r
+ <returns>1 for a red node, 0 for a black node</returns>\r
+ <remarks>For jsw_rbtree.c internal use only</remarks>\r
+*/\r
+static int is_red ( jsw_rbnode_t *root )\r
+{\r
+ return root != NULL && root->red == 1;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Performs a single red black rotation in the specified direction\r
+ This function assumes that all nodes are valid for a rotation\r
+ <summary>\r
+ <param name="root">The original root to rotate around</param>\r
+ <param name="dir">The direction to rotate (0 = left, 1 = right)</param>\r
+ <returns>The new root ater rotation</returns>\r
+ <remarks>For jsw_rbtree.c internal use only</remarks>\r
+*/\r
+static jsw_rbnode_t *jsw_single ( jsw_rbnode_t *root, int dir )\r
+{\r
+ jsw_rbnode_t *save = root->link[!dir];\r
+\r
+ root->link[!dir] = save->link[dir];\r
+ save->link[dir] = root;\r
+\r
+ root->red = 1;\r
+ save->red = 0;\r
+\r
+ return save;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Performs a double red black rotation in the specified direction\r
+ This function assumes that all nodes are valid for a rotation\r
+ <summary>\r
+ <param name="root">The original root to rotate around</param>\r
+ <param name="dir">The direction to rotate (0 = left, 1 = right)</param>\r
+ <returns>The new root after rotation</returns>\r
+ <remarks>For jsw_rbtree.c internal use only</remarks>\r
+*/\r
+static jsw_rbnode_t *jsw_double ( jsw_rbnode_t *root, int dir )\r
+{\r
+ root->link[!dir] = jsw_single ( root->link[!dir], !dir );\r
+\r
+ return jsw_single ( root, dir );\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Creates an initializes a new red black node with a copy of\r
+ the data. This function does not insert the new node into a tree\r
+ <summary>\r
+ <param name="tree">The red black tree this node is being created for</param>\r
+ <param name="data">The data value that will be stored in this node</param>\r
+ <returns>A pointer to the new node</returns>\r
+ <remarks>\r
+ For jsw_rbtree.c internal use only. The data for this node must\r
+ be freed using the same tree's rel function. The returned pointer\r
+ must be freed using C's free function\r
+ </remarks>\r
+*/\r
+static jsw_rbnode_t *new_node ( jsw_rbtree_t *tree, void *data )\r
+{\r
+ jsw_rbnode_t *rn = (jsw_rbnode_t *)malloc ( sizeof *rn );\r
+\r
+ if ( rn == NULL )\r
+ return NULL;\r
+\r
+ rn->red = 1;\r
+ rn->data = tree->dup ( data );\r
+ rn->link[0] = rn->link[1] = NULL;\r
+\r
+ return rn;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Creates and initializes an empty red black tree with\r
+ user-defined comparison, data copy, and data release operations\r
+ <summary>\r
+ <param name="cmp">User-defined data comparison function</param>\r
+ <param name="dup">User-defined data copy function</param>\r
+ <param name="rel">User-defined data release function</param>\r
+ <returns>A pointer to the new tree</returns>\r
+ <remarks>\r
+ The returned pointer must be released with jsw_rbdelete\r
+ </remarks>\r
+*/\r
+jsw_rbtree_t *jsw_rbnew ( cmp_f cmp, dup_f dup, rel_f rel )\r
+{\r
+ jsw_rbtree_t *rt = (jsw_rbtree_t *)malloc ( sizeof *rt );\r
+\r
+ if ( rt == NULL )\r
+ return NULL;\r
+\r
+ rt->root = NULL;\r
+ rt->cmp = cmp;\r
+ rt->dup = dup;\r
+ rt->rel = rel;\r
+ rt->size = 0;\r
+\r
+ return rt;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Releases a valid red black tree\r
+ <summary>\r
+ <param name="tree">The tree to release</param>\r
+ <remarks>\r
+ The tree must have been created using jsw_rbnew\r
+ </remarks>\r
+*/\r
+void jsw_rbdelete ( jsw_rbtree_t *tree )\r
+{\r
+ jsw_rbnode_t *it = tree->root;\r
+ jsw_rbnode_t *save;\r
+\r
+ /*\r
+ Rotate away the left links so that\r
+ we can treat this like the destruction\r
+ of a linked list\r
+ */\r
+ while ( it != NULL ) {\r
+ if ( it->link[0] == NULL ) {\r
+ /* No left links, just kill the node and move on */\r
+ save = it->link[1];\r
+ tree->rel ( it->data );\r
+ free ( it );\r
+ }\r
+ else {\r
+ /* Rotate away the left link and check again */\r
+ save = it->link[0];\r
+ it->link[0] = save->link[1];\r
+ save->link[1] = it;\r
+ }\r
+\r
+ it = save;\r
+ }\r
+\r
+ free ( tree );\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Search for a copy of the specified\r
+ node data in a red black tree\r
+ <summary>\r
+ <param name="tree">The tree to search</param>\r
+ <param name="data">The data value to search for</param>\r
+ <returns>\r
+ A pointer to the data value stored in the tree,\r
+ or a null pointer if no data could be found\r
+ </returns>\r
+*/\r
+void *jsw_rbfind ( jsw_rbtree_t *tree, void *data )\r
+{\r
+ jsw_rbnode_t *it = tree->root;\r
+\r
+ while ( it != NULL ) {\r
+ int cmp = tree->cmp ( it->data, data );\r
+\r
+ if ( cmp == 0 )\r
+ break;\r
+\r
+ /*\r
+ If the tree supports duplicates, they should be\r
+ chained to the right subtree for this to work\r
+ */\r
+ it = it->link[cmp < 0];\r
+ }\r
+\r
+ return it == NULL ? NULL : it->data;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Insert a copy of the user-specified\r
+ data into a red black tree\r
+ <summary>\r
+ <param name="tree">The tree to insert into</param>\r
+ <param name="data">The data value to insert</param>\r
+ <returns>\r
+ 1 if the value was inserted successfully,\r
+ 0 if the insertion failed for any reason\r
+ </returns>\r
+*/\r
+int jsw_rbinsert ( jsw_rbtree_t *tree, void *data )\r
+{\r
+ if ( tree->root == NULL ) {\r
+ /*\r
+ We have an empty tree; attach the\r
+ new node directly to the root\r
+ */\r
+ tree->root = new_node ( tree, data );\r
+\r
+ if ( tree->root == NULL )\r
+ return 0;\r
+ }\r
+ else {\r
+ jsw_rbnode_t head = {0}; /* False tree root */\r
+ jsw_rbnode_t *g, *t; /* Grandparent & parent */\r
+ jsw_rbnode_t *p, *q; /* Iterator & parent */\r
+ int dir = 0, last = 0;\r
+\r
+ /* Set up our helpers */\r
+ t = &head;\r
+ g = p = NULL;\r
+ q = t->link[1] = tree->root;\r
+\r
+ /* Search down the tree for a place to insert */\r
+ for ( ; ; ) {\r
+ if ( q == NULL ) {\r
+ /* Insert a new node at the first null link */\r
+ p->link[dir] = q = new_node ( tree, data );\r
+\r
+ if ( q == NULL )\r
+ return 0;\r
+ }\r
+ else if ( is_red ( q->link[0] ) && is_red ( q->link[1] ) ) {\r
+ /* Simple red violation: color flip */\r
+ q->red = 1;\r
+ q->link[0]->red = 0;\r
+ q->link[1]->red = 0;\r
+ }\r
+\r
+ if ( is_red ( q ) && is_red ( p ) ) {\r
+ /* Hard red violation: rotations necessary */\r
+ int dir2 = t->link[1] == g;\r
+\r
+ if ( q == p->link[last] )\r
+ t->link[dir2] = jsw_single ( g, !last );\r
+ else\r
+ t->link[dir2] = jsw_double ( g, !last );\r
+ }\r
+\r
+ /*\r
+ Stop working if we inserted a node. This\r
+ check also disallows duplicates in the tree\r
+ */\r
+ if ( tree->cmp ( q->data, data ) == 0 )\r
+ break;\r
+\r
+ last = dir;\r
+ dir = tree->cmp ( q->data, data ) < 0;\r
+\r
+ /* Move the helpers down */\r
+ if ( g != NULL )\r
+ t = g;\r
+\r
+ g = p, p = q;\r
+ q = q->link[dir];\r
+ }\r
+\r
+ /* Update the root (it may be different) */\r
+ tree->root = head.link[1];\r
+ }\r
+\r
+ /* Make the root black for simplified logic */\r
+ tree->root->red = 0;\r
+ ++tree->size;\r
+\r
+ return 1;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Remove a node from a red black tree\r
+ that matches the user-specified data\r
+ <summary>\r
+ <param name="tree">The tree to remove from</param>\r
+ <param name="data">The data value to search for</param>\r
+ <returns>\r
+ 1 if the value was removed successfully,\r
+ 0 if the removal failed for any reason\r
+ </returns>\r
+ <remarks>\r
+ The most common failure reason should be\r
+ that the data was not found in the tree\r
+ </remarks>\r
+*/\r
+int jsw_rberase ( jsw_rbtree_t *tree, void *data )\r
+{\r
+ if ( tree->root != NULL ) {\r
+ jsw_rbnode_t head = {0}; /* False tree root */\r
+ jsw_rbnode_t *q, *p, *g; /* Helpers */\r
+ jsw_rbnode_t *f = NULL; /* Found item */\r
+ int dir = 1;\r
+\r
+ /* Set up our helpers */\r
+ q = &head;\r
+ g = p = NULL;\r
+ q->link[1] = tree->root;\r
+\r
+ /*\r
+ Search and push a red node down\r
+ to fix red violations as we go\r
+ */\r
+ while ( q->link[dir] != NULL ) {\r
+ int last = dir;\r
+\r
+ /* Move the helpers down */\r
+ g = p, p = q;\r
+ q = q->link[dir];\r
+ dir = tree->cmp ( q->data, data ) < 0;\r
+\r
+ /*\r
+ Save the node with matching data and keep\r
+ going; we'll do removal tasks at the end\r
+ */\r
+ if ( tree->cmp ( q->data, data ) == 0 )\r
+ f = q;\r
+\r
+ /* Push the red node down with rotations and color flips */\r
+ if ( !is_red ( q ) && !is_red ( q->link[dir] ) ) {\r
+ if ( is_red ( q->link[!dir] ) )\r
+ p = p->link[last] = jsw_single ( q, dir );\r
+ else if ( !is_red ( q->link[!dir] ) ) {\r
+ jsw_rbnode_t *s = p->link[!last];\r
+\r
+ if ( s != NULL ) {\r
+ if ( !is_red ( s->link[!last] ) && !is_red ( s->link[last] ) ) {\r
+ /* Color flip */\r
+ p->red = 0;\r
+ s->red = 1;\r
+ q->red = 1;\r
+ }\r
+ else {\r
+ int dir2 = g->link[1] == p;\r
+\r
+ if ( is_red ( s->link[last] ) )\r
+ g->link[dir2] = jsw_double ( p, last );\r
+ else if ( is_red ( s->link[!last] ) )\r
+ g->link[dir2] = jsw_single ( p, last );\r
+\r
+ /* Ensure correct coloring */\r
+ q->red = g->link[dir2]->red = 1;\r
+ g->link[dir2]->link[0]->red = 0;\r
+ g->link[dir2]->link[1]->red = 0;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Replace and remove the saved node */\r
+ if ( f != NULL ) {\r
+ tree->rel ( f->data );\r
+ f->data = q->data;\r
+ p->link[p->link[1] == q] =\r
+ q->link[q->link[0] == NULL];\r
+ free ( q );\r
+ }\r
+\r
+ /* Update the root (it may be different) */\r
+ tree->root = head.link[1];\r
+\r
+ /* Make the root black for simplified logic */\r
+ if ( tree->root != NULL )\r
+ tree->root->red = 0;\r
+\r
+ --tree->size;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Gets the number of nodes in a red black tree\r
+ <summary>\r
+ <param name="tree">The tree to calculate a size for</param>\r
+ <returns>The number of nodes in the tree</returns>\r
+*/\r
+size_t jsw_rbsize ( jsw_rbtree_t *tree )\r
+{\r
+ return tree->size;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Create a new traversal object\r
+ <summary>\r
+ <returns>A pointer to the new object</returns>\r
+ <remarks>\r
+ The traversal object is not initialized until\r
+ jsw_rbtfirst or jsw_rbtlast are called.\r
+ The pointer must be released with jsw_rbtdelete\r
+ </remarks>\r
+*/\r
+jsw_rbtrav_t *jsw_rbtnew ( void )\r
+{\r
+ return (jsw_rbtrav_t*)malloc ( sizeof ( jsw_rbtrav_t ) );\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Release a traversal object\r
+ <summary>\r
+ <param name="trav">The object to release</param>\r
+ <remarks>\r
+ The object must have been created with jsw_rbtnew\r
+ </remarks>\r
+*/\r
+void jsw_rbtdelete ( jsw_rbtrav_t *trav )\r
+{\r
+ free ( trav );\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Initialize a traversal object. The user-specified\r
+ direction determines whether to begin traversal at the\r
+ smallest or largest valued node\r
+ <summary>\r
+ <param name="trav">The traversal object to initialize</param>\r
+ <param name="tree">The tree that the object will be attached to</param>\r
+ <param name="dir">\r
+ The direction to traverse (0 = ascending, 1 = descending)\r
+ </param>\r
+ <returns>A pointer to the smallest or largest data value</returns>\r
+ <remarks>For jsw_rbtree.c internal use only</remarks>\r
+*/\r
+static void *start ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree, int dir )\r
+{\r
+ trav->tree = tree;\r
+ trav->it = tree->root;\r
+ trav->top = 0;\r
+\r
+ /* Save the path for later traversal */\r
+ if ( trav->it != NULL ) {\r
+ while ( trav->it->link[dir] != NULL ) {\r
+ trav->path[trav->top++] = trav->it;\r
+ trav->it = trav->it->link[dir];\r
+ }\r
+ }\r
+\r
+ return trav->it == NULL ? NULL : trav->it->data;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Traverse a red black tree in the user-specified direction\r
+ <summary>\r
+ <param name="trav">The initialized traversal object</param>\r
+ <param name="dir">\r
+ The direction to traverse (0 = ascending, 1 = descending)\r
+ </param>\r
+ <returns>\r
+ A pointer to the next data value in the specified direction\r
+ </returns>\r
+ <remarks>For jsw_rbtree.c internal use only</remarks>\r
+*/\r
+static void *move ( jsw_rbtrav_t *trav, int dir )\r
+{\r
+ if ( trav->it->link[dir] != NULL ) {\r
+ /* Continue down this branch */\r
+ trav->path[trav->top++] = trav->it;\r
+ trav->it = trav->it->link[dir];\r
+\r
+ while ( trav->it->link[!dir] != NULL ) {\r
+ trav->path[trav->top++] = trav->it;\r
+ trav->it = trav->it->link[!dir];\r
+ }\r
+ }\r
+ else {\r
+ /* Move to the next branch */\r
+ jsw_rbnode_t *last;\r
+\r
+ do {\r
+ if ( trav->top == 0 ) {\r
+ trav->it = NULL;\r
+ break;\r
+ }\r
+\r
+ last = trav->it;\r
+ trav->it = trav->path[--trav->top];\r
+ } while ( last == trav->it->link[dir] );\r
+ }\r
+\r
+ return trav->it == NULL ? NULL : trav->it->data;\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Initialize a traversal object to the smallest valued node\r
+ <summary>\r
+ <param name="trav">The traversal object to initialize</param>\r
+ <param name="tree">The tree that the object will be attached to</param>\r
+ <returns>A pointer to the smallest data value</returns>\r
+*/\r
+void *jsw_rbtfirst ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree )\r
+{\r
+ return start ( trav, tree, 0 ); /* Min value */\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Initialize a traversal object to the largest valued node\r
+ <summary>\r
+ <param name="trav">The traversal object to initialize</param>\r
+ <param name="tree">The tree that the object will be attached to</param>\r
+ <returns>A pointer to the largest data value</returns>\r
+*/\r
+void *jsw_rbtlast ( jsw_rbtrav_t *trav, jsw_rbtree_t *tree )\r
+{\r
+ return start ( trav, tree, 1 ); /* Max value */\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Traverse to the next value in ascending order\r
+ <summary>\r
+ <param name="trav">The initialized traversal object</param>\r
+ <returns>A pointer to the next value in ascending order</returns>\r
+*/\r
+void *jsw_rbtnext ( jsw_rbtrav_t *trav )\r
+{\r
+ return move ( trav, 1 ); /* Toward larger items */\r
+}\r
+\r
+/**\r
+ <summary>\r
+ Traverse to the next value in descending order\r
+ <summary>\r
+ <param name="trav">The initialized traversal object</param>\r
+ <returns>A pointer to the next value in descending order</returns>\r
+*/\r
+void *jsw_rbtprev ( jsw_rbtrav_t *trav )\r
+{\r
+ return move ( trav, 0 ); /* Toward smaller items */\r
+}
\ No newline at end of file