/** * c_rbnode_next_postorder() - return next node in post-order * @n: current node, or NULL * * This returns the next node to @n, based on a left-to-right post-order * traversal. If @n is NULL, the root node, or unlinked, this returns NULL. * * This implements a left-to-right post-order traversal: First visit the left * child of a node, then the right, and lastly the node itself. Children are * traversed recursively. * * This function can be used to implement a left-to-right post-order traversal: * * for (n = c_rbtree_first_postorder(t); n; n = c_rbnode_next_postorder(n)) * visit(n); * * Worst case runtime (n: number of elements in tree): O(log(n)) * * Return: Pointer to next node, or NULL. */ _c_public_ CRBNode *c_rbnode_next_postorder(CRBNode *n) { CRBNode *p; if (!c_rbnode_is_linked(n)) return NULL; p = c_rbnode_parent(n); if (p && n == p->left && p->right) return c_rbnode_leftdeepest(p->right); return p; }
/** * c_rbnode_prev() - return previous node * @n: current node, or NULL * * An RB-Tree always defines a linear order of its elements. This function * returns the logically previous node to @n. If @n is NULL, the first node or * unlinked, this returns NULL. * * Worst case runtime (n: number of elements in tree): O(log(n)) * * Return: Pointer to previous node, or NULL. */ _c_public_ CRBNode *c_rbnode_prev(CRBNode *n) { CRBNode *p; if (!c_rbnode_is_linked(n)) return NULL; if (n->left) return c_rbnode_rightmost(n->left); while ((p = c_rbnode_parent(n)) && n == p->left) n = p; return p; }
/** * c_rbnode_prev_postorder() - return previous node in post-order * @n: current node, or NULL * * This returns the previous node to @n, based on a left-to-right post-order * traversal. That is, it is the inverse operation to c_rbnode_next_postorder(). * If @n is NULL, the left-deepest node, or unlinked, this returns NULL. * * This function returns the logical previous node in a directed post-order * traversal. That is, it effectively does a pre-order traversal (since a * reverse post-order traversal is a pre-order traversal). This function does * NOT do a right-to-left post-order traversal! In other words, the following * invariant is guaranteed, if c_rbnode_next_postorder(n) is non-NULL: * * n == c_rbnode_prev_postorder(c_rbnode_next_postorder(n)) * * This function can be used to implement a right-to-left pre-order traversal, * using the fact that a reverse post-order traversal is also a valid pre-order * traversal: * * for (n = c_rbtree_last_postorder(t); n; n = c_rbnode_prev_postorder(n)) * visit(n); * * This would effectively perform a right-to-left pre-order traversal: first * visit a parent, then its right child, then its left child. Both children are * traversed recursively. * * Worst case runtime (n: number of elements in tree): O(log(n)) * * Return: Pointer to previous node in post-order, or NULL. */ _c_public_ CRBNode *c_rbnode_prev_postorder(CRBNode *n) { CRBNode *p; if (!c_rbnode_is_linked(n)) return NULL; if (n->right) return n->right; if (n->left) return n->left; while ((p = c_rbnode_parent(n))) { if (p->left && n != p->left) return p->left; n = p; } return NULL; }
* This function does *NOT* perform a full swap, nor does it touch any 'parent' * pointer. * * The sole purpose of this function is to shortcut left/right conditionals * like this: * * if (old == old->parent->left) * old->parent->left = new; * else * old->parent->right = new; * * That's it! If @old is the root node, this will do nothing. The caller must * employ c_rbnode_pop_root() and c_rbnode_push_root(). */ static inline void c_rbnode_swap_child(CRBNode *old, CRBNode *new) { CRBNode *p = c_rbnode_parent(old); if (p) { if (p->left == old) c_rbtree_store(&p->left, new); else c_rbtree_store(&p->right, new); } } /** * c_rbtree_move() - move tree * @to: destination tree * @from: source tree * * This imports the entire tree from @from into @to. @to must be empty! @from
static size_t validate(CRBTree *t) { unsigned int i_black, n_black; CRBNode *n, *p, *o; size_t count = 0; assert(t); assert(!t->root || c_rbnode_is_black(t->root)); /* traverse to left-most child, count black nodes */ i_black = 0; n = t->root; while (n && n->left) { if (c_rbnode_is_black(n)) ++i_black; n = n->left; } n_black = i_black; /* * Traverse tree and verify correctness: * 1) A node is either red or black * 2) The root is black * 3) All leaves are black * 4) Every red node must have two black child nodes * 5) Every path to a leaf contains the same number of black nodes * * Note that NULL nodes are considered black, which is why we don't * check for 3). */ o = NULL; while (n) { ++count; /* verify natural order */ assert(n > o); o = n; /* verify consistency */ assert(!n->right || c_rbnode_parent(n->right) == n); assert(!n->left || c_rbnode_parent(n->left) == n); /* verify 2) */ if (!c_rbnode_parent(n)) assert(c_rbnode_is_black(n)); if (c_rbnode_is_red(n)) { /* verify 4) */ assert(!n->left || c_rbnode_is_black(n->left)); assert(!n->right || c_rbnode_is_black(n->right)); } else { /* verify 1) */ assert(c_rbnode_is_black(n)); } /* verify 5) */ if (!n->left && !n->right) assert(i_black == n_black); /* get next node */ if (n->right) { n = n->right; if (c_rbnode_is_black(n)) ++i_black; while (n->left) { n = n->left; if (c_rbnode_is_black(n)) ++i_black; } } else { while ((p = c_rbnode_parent(n)) && n == p->right) { n = p; if (c_rbnode_is_black(p->right)) --i_black; } n = p; if (p && c_rbnode_is_black(p->left)) --i_black; } } return count; }