Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; ifnot, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/ /********************************************************************//**
Red-Black tree implementation
(c) 2007 Oracle/Innobase Oy
Created 2007-03-20 Sunny Bains
***********************************************************************/
#include"ut0rbt.h" #include"ut0new.h"
/**********************************************************************//**
Definition of a red-black tree
==============================
A red-black tree is a binary search tree which has the following
red-black properties:
1. Every node is either red or black. 2. Every leaf (NULL - in our case tree->nil) is black. 3. If a node is red, then both its children are black. 4. Every simple path from a node to a descendant leaf contains the
same number of black nodes.
from (3) above, the implication is that on any path from the root
to a leaf, red nodes must not be adjacent.
However, any number of black nodes may appear in a sequence.
*/
#ifdefined UNIV_DEBUG || defined IB_RBT_TESTING /**********************************************************************//**
Verify that the keys are in order.
@returnTRUE of OK. FALSEifnot ordered */ static
ibool
rbt_check_ordering( /*===============*/ const ib_rbt_t* tree) /*!< in: tree to verify */
{ const ib_rbt_node_t* node; const ib_rbt_node_t* prev = NULL;
/* Iterate over all the nodes, comparing each node with the prev */ for (node = rbt_first(tree); node; node = rbt_next(tree, prev)) {
if (prev) { int result;
if (tree->cmp_arg) {
result = tree->compare_with_arg(
tree->cmp_arg, prev->value,
node->value);
} else {
result = tree->compare(
prev->value, node->value);
}
if (result >= 0) { return(FALSE);
}
}
prev = node;
}
return(TRUE);
}
/**********************************************************************//**
Check that every path from the root to the leaves has the same count.
Count is expressed in the number of black nodes.
@return0 on failure else black height of the subtree */ static
ibool
rbt_count_black_nodes( /*==================*/ const ib_rbt_t* tree, /*!< in: tree to verify */ const ib_rbt_node_t* node) /*!< in: start of sub-tree */
{
ulint result;
if (node != tree->nil) {
ulint left_height = rbt_count_black_nodes(tree, node->left);
/**********************************************************************//**
Turn the node's right child's left sub-tree into node's right sub-tree. This will also make node's right child it's parent. */ static void
rbt_rotate_left( /*============*/ const ib_rbt_node_t* nil, /*!< in: nil node of the tree */
ib_rbt_node_t* node) /*!< in: node to rotate */
{
ib_rbt_node_t* right = node->right;
node->right = right->left;
if (right->left != nil) {
right->left->parent = node;
}
/* Right's new parent was node's parent. */
right->parent = node->parent;
/* Since root's parent is tree->nil and root->parent->left points
back to root, we can avoid the check. */ if (node == node->parent->left) { /* Node was on the left of its parent. */
node->parent->left = right;
} else { /* Node must have been on the right. */
node->parent->right = right;
}
/* Finally, put node on right's left. */
right->left = node;
node->parent = right;
}
/**********************************************************************//**
Turn the node's left child's right sub-tree into node's left sub-tree. This also make node's left child it's parent. */ static void
rbt_rotate_right( /*=============*/ const ib_rbt_node_t* nil, /*!< in: nil node of tree */
ib_rbt_node_t* node) /*!< in: node to rotate */
{
ib_rbt_node_t* left = node->left;
node->left = left->right;
if (left->right != nil) {
left->right->parent = node;
}
/* Left's new parent was node's parent. */
left->parent = node->parent;
/* Since root's parent is tree->nil and root->parent->left points
back to root, we can avoid the check. */ if (node == node->parent->right) { /* Node was on the left of its parent. */
node->parent->right = left;
} else { /* Node must have been on the left. */
node->parent->left = left;
}
/* Finally, put node on left's right. */
left->right = node;
node->parent = left;
}
/**********************************************************************//**
Append a node to the tree. */ static
ib_rbt_node_t*
rbt_tree_add_child( /*===============*/ const ib_rbt_t* tree,
ib_rbt_bound_t* parent,
ib_rbt_node_t* node)
{ /* Cast away the const. */
ib_rbt_node_t* last = (ib_rbt_node_t*) parent->last;
if (parent == grand_parent->left) {
ib_rbt_node_t* uncle = grand_parent->right;
if (uncle->color == IB_RBT_RED) {
/* Case 1 - change the colors. */
uncle->color = IB_RBT_BLACK;
parent->color = IB_RBT_BLACK;
grand_parent->color = IB_RBT_RED;
/* Move node up the tree. */
node = grand_parent;
} else {
if (node == parent->right) { /* Right is a black node and node is totheright,case2-movenode
up and rotate. */
node = parent;
rbt_rotate_left(nil, node);
}
grand_parent = node->parent->parent;
/* Case 3. */
node->parent->color = IB_RBT_BLACK;
grand_parent->color = IB_RBT_RED;
/* Case 1 - change the colors. */
uncle->color = IB_RBT_BLACK;
parent->color = IB_RBT_BLACK;
grand_parent->color = IB_RBT_RED;
/* Move node up the tree. */
node = grand_parent;
} else {
if (node == parent->left) { /* Left is a black node and node is to theright,case2-movenodeupand
rotate. */
node = parent;
rbt_rotate_right(nil, node);
}
grand_parent = node->parent->parent;
/* Case 3. */
node->parent->color = IB_RBT_BLACK;
grand_parent->color = IB_RBT_RED;
rbt_rotate_left(nil, grand_parent);
}
}
parent = node->parent;
}
/* Color the root black. */
ROOT(tree)->color = IB_RBT_BLACK;
}
/**********************************************************************//**
Find the given node's successor.
@return successor node or NULL if no successor */ static
ib_rbt_node_t*
rbt_find_successor( /*===============*/ const ib_rbt_t* tree, /*!< in: rb tree */ const ib_rbt_node_t* current) /*!< in: this is declared const becauseitcanbecalledvia
rbt_next() */
{ const ib_rbt_node_t* nil = tree->nil;
ib_rbt_node_t* next = current->right;
/* Is there a sub-tree to the right that we can follow. */ if (next != nil) {
/* Follow the left most links of the current right child. */ while (next->left != nil) {
next = next->left;
}
} else { /* We will have to go up the tree to find the successor. */
ib_rbt_node_t* parent = current->parent;
/* Cast away the const. */
next = (ib_rbt_node_t*) current;
while (parent != tree->root && next == parent->right) {
next = parent;
parent = next->parent;
}
next = (parent == tree->root) ? NULL : parent;
}
return(next);
}
/**********************************************************************//**
Find the given node's precedecessor.
@return predecessor node or NULL if no predecessor */ static
ib_rbt_node_t*
rbt_find_predecessor( /*=================*/ const ib_rbt_t* tree, /*!< in: rb tree */ const ib_rbt_node_t* current) /*!< in: this is declared const becauseitcanbecalledvia
rbt_prev() */
{ const ib_rbt_node_t* nil = tree->nil;
ib_rbt_node_t* prev = current->left;
/* Is there a sub-tree to the left that we can follow. */ if (prev != nil) {
/* Follow the right most links of the current left child. */ while (prev->right != nil) {
prev = prev->right;
}
} else { /* We will have to go up the tree to find the precedecessor. */
ib_rbt_node_t* parent = current->parent;
/* Cast away the const. */
prev = (ib_rbt_node_t*) current;
/**********************************************************************//**
Replace node with child. After applying transformations eject becomes
an orphan. */ static void
rbt_eject_node( /*===========*/
ib_rbt_node_t* eject, /*!< in: node to eject */
ib_rbt_node_t* node) /*!< in: node to replace with */
{ /* Update the to be ejected node's parent's child pointers. */ if (eject->parent->left == eject) {
eject->parent->left = node;
} elseif (eject->parent->right == eject) {
eject->parent->right = node;
} else {
ut_a(0);
} /* eject is now an orphan but otherwise its pointers
and color are left intact. */
node->parent = eject->parent;
}
/**********************************************************************//**
Replace a node with another node. */ static void
rbt_replace_node( /*=============*/
ib_rbt_node_t* replace, /*!< in: node to replace */
ib_rbt_node_t* node) /*!< in: node to replace with */
{
ib_rbt_color_t color = node->color;
/**********************************************************************//**
Detach node from the tree replacing it with one of it's children.
@return the child node that now occupies the position of the detached node */ static
ib_rbt_node_t*
rbt_detach_node( /*============*/ const ib_rbt_t* tree, /*!< in: rb tree */
ib_rbt_node_t* node) /*!< in: node to detach */
{
ib_rbt_node_t* child; const ib_rbt_node_t* nil = tree->nil;
if (node->left != nil && node->right != nil) { /* Case where the node to be deleted has two children. */
ib_rbt_node_t* successor = rbt_find_successor(tree, node);
/**********************************************************************//** Delete the node and rebalance the tree if necessary */ static void
rbt_remove_node_and_rebalance( /*==========================*/
ib_rbt_t* tree, /*!< in: rb tree */
ib_rbt_node_t* node) /*!< in: node to remove */
{ /* Detach node and get the node that will be used
as rebalance start. */
ib_rbt_node_t* child = rbt_detach_node(tree, node);
if (node->color == IB_RBT_BLACK) {
ib_rbt_node_t* last = child;
/* Note that we have removed a node from the tree. */
--tree->n_nodes;
}
/**********************************************************************//**
Recursively free the nodes. */ static void
rbt_free_node( /*==========*/
ib_rbt_node_t* node, /*!< in: node to free */
ib_rbt_node_t* nil) /*!< in: rb tree nil node */
{ if (node != nil) {
rbt_free_node(node->left, nil);
rbt_free_node(node->right, nil);
ut_free(node);
}
}
/**********************************************************************//**
Free all the nodes and free the tree. */ void
rbt_free( /*=====*/
ib_rbt_t* tree) /*!< in: rb tree to free */
{
rbt_free_node(tree->root, tree->nil);
ut_free(tree->nil);
ut_free(tree);
}
/**********************************************************************//**
Create an instance of a red black tree, whose comparison function takes
an argument
@return an empty rb tree */
ib_rbt_t*
rbt_create_arg_cmp( /*===============*/
size_t sizeof_value, /*!< in: sizeof data item */
ib_rbt_arg_compare
compare, /*!< in: fn to compare items */ void* cmp_arg) /*!< in: compare fn arg */
{
ib_rbt_t* tree;
ut_a(cmp_arg);
tree = rbt_create(sizeof_value, NULL);
tree->cmp_arg = cmp_arg;
tree->compare_with_arg = compare;
return(tree);
}
/**********************************************************************//**
Create an instance of a red black tree.
@return an empty rb tree */
ib_rbt_t*
rbt_create( /*=======*/
size_t sizeof_value, /*!< in: sizeof data item */
ib_rbt_compare compare) /*!< in: fn to compare items */
{
ib_rbt_t* tree;
ib_rbt_node_t* node;
tree = (ib_rbt_t*) ut_zalloc_nokey(sizeof(*tree));
/* Create the "fake" root, the real root node will be the
left child of this node. */
node = tree->root = (ib_rbt_node_t*) ut_zalloc_nokey(sizeof(*node));
/**********************************************************************//**
Generic insert of a value in the rb tree.
@return inserted node */ const ib_rbt_node_t*
rbt_insert( /*=======*/
ib_rbt_t* tree, /*!< in: rb tree */ constvoid* key, /*!< in: key for ordering */ constvoid* value) /*!< in: value of key, this value
is copied to the node */
{
ib_rbt_node_t* node;
/* Create the node that will hold the value data. */
node = (ib_rbt_node_t*) ut_malloc_nokey(SIZEOF_NODE(tree));
/* Insert in the tree in the usual way. */
rbt_tree_insert(tree, key, node);
rbt_balance_tree(tree, node);
++tree->n_nodes;
return(node);
}
/**********************************************************************//**
Add a new node to the tree, useful for data that is pre-sorted.
@return appended node */ const ib_rbt_node_t*
rbt_add_node( /*=========*/
ib_rbt_t* tree, /*!< in: rb tree */
ib_rbt_bound_t* parent, /*!< in: bounds */ constvoid* value) /*!< in: this value is copied
to the node */
{
ib_rbt_node_t* node;
/* Create the node that will hold the value data */
node = (ib_rbt_node_t*) ut_malloc_nokey(SIZEOF_NODE(tree));
/* If tree is empty */ if (parent->last == NULL) {
parent->last = tree->root;
}
/* Append the node, the hope here is that the caller knows
what s/he is doing. */
rbt_tree_add_child(tree, parent, node);
rbt_balance_tree(tree, node);
++tree->n_nodes;
#ifdefined UNIV_DEBUG || defined IB_RBT_TESTING
ut_a(rbt_validate(tree)); #endif return(node);
}
/**********************************************************************//**
Find a matching node in the rb tree.
@return NULL ifnot found else the node where key was found */ static const ib_rbt_node_t*
rbt_lookup( /*=======*/ const ib_rbt_t* tree, /*!< in: rb tree */ constvoid* key) /*!< in: key to use for search */
{ const ib_rbt_node_t* current = ROOT(tree);
/* Regular binary search. */ while (current != tree->nil) { int result;
if (tree->cmp_arg) {
result = tree->compare_with_arg(
tree->cmp_arg, key, current->value);
} else {
result = tree->compare(key, current->value);
}
if (result < 0) {
current = current->left;
} elseif (result > 0) {
current = current->right;
} else { break;
}
}
return(current != tree->nil ? current : NULL);
}
/**********************************************************************//** Delete a node indentified by key.
@returnTRUEif success FALSEifnot found */
ibool
rbt_delete( /*=======*/
ib_rbt_t* tree, /*!< in: rb tree */ constvoid* key) /*!< in: key to delete */
{
ibool deleted = FALSE;
ib_rbt_node_t* node = (ib_rbt_node_t*) rbt_lookup(tree, key);
if (node) {
rbt_remove_node_and_rebalance(tree, node);
ut_free(node);
deleted = TRUE;
}
return(deleted);
}
/**********************************************************************//**
Remove a node from the rb tree, the node is not free'd, that is the
callers responsibility.
@return deleted node but without the const */
ib_rbt_node_t*
rbt_remove_node( /*============*/
ib_rbt_t* tree, /*!< in: rb tree */ const ib_rbt_node_t* const_node) /*!< in: node to delete, this isafudgeanddeclaredconst becausethecallercanaccess
only const nodes */
{ /* Cast away the const. */
rbt_remove_node_and_rebalance(tree, (ib_rbt_node_t*) const_node);
/* This is to make it easier to do something like this: ut_free(rbt_remove_node(node));
*/
return((ib_rbt_node_t*) const_node);
}
/**********************************************************************//**
Find the node that has the greatest key that is <= key.
@return value of result */ int
rbt_search( /*=======*/ const ib_rbt_t* tree, /*!< in: rb tree */
ib_rbt_bound_t* parent, /*!< in: search bounds */ constvoid* key) /*!< in: key to search */
{
ib_rbt_node_t* current = ROOT(tree);
/* Every thing is greater than the NULL root. */
parent->result = 1;
parent->last = NULL;
if (parent->result > 0) {
current = current->right;
} elseif (parent->result < 0) {
current = current->left;
} else { break;
}
}
return(parent->result);
}
/**********************************************************************//**
Find the node that has the greatest key that is <= key. But use the
supplied comparison function.
@return value of result */ int
rbt_search_cmp( /*===========*/ const ib_rbt_t* tree, /*!< in: rb tree */
ib_rbt_bound_t* parent, /*!< in: search bounds */ constvoid* key, /*!< in: key to search */
ib_rbt_compare compare, /*!< in: fn to compare items */
ib_rbt_arg_compare
arg_compare) /*!< in: fn to compare items
with argument */
{
ib_rbt_node_t* current = ROOT(tree);
/* Every thing is greater than the NULL root. */
parent->result = 1;
parent->last = NULL;
if (parent->result > 0) {
current = current->right;
} elseif (parent->result < 0) {
current = current->left;
} else { break;
}
}
return(parent->result);
}
/**********************************************************************//** Return the left most node in the tree. */ const ib_rbt_node_t*
rbt_first( /*======*/ /* out leftmost node or NULL */ const ib_rbt_t* tree) /* in: rb tree */
{
ib_rbt_node_t* first = NULL;
ib_rbt_node_t* current = ROOT(tree);
while (current != tree->nil) {
first = current;
current = current->left;
}
return(first);
}
/**********************************************************************//** Return the right most node in the tree.
@return the rightmost node or NULL */ const ib_rbt_node_t*
rbt_last( /*=====*/ const ib_rbt_t* tree) /*!< in: rb tree */
{
ib_rbt_node_t* last = NULL;
ib_rbt_node_t* current = ROOT(tree);
while (current != tree->nil) {
last = current;
current = current->right;
}
return(last);
}
/**********************************************************************//** Return the next node.
@return node next from current */ const ib_rbt_node_t*
rbt_next( /*=====*/ const ib_rbt_t* tree, /*!< in: rb tree */ const ib_rbt_node_t* current) /*!< in: current node */
{ return(current ? rbt_find_successor(tree, current) : NULL);
}
/**********************************************************************//** Return the previous node.
@return node prev from current */ const ib_rbt_node_t*
rbt_prev( /*=====*/ const ib_rbt_t* tree, /*!< in: rb tree */ const ib_rbt_node_t* current) /*!< in: current node */
{ return(current ? rbt_find_predecessor(tree, current) : NULL);
}
/**********************************************************************//**
Merge the node from dst into src. Return the number of nodes merged.
@return no. of recs merged */
ulint
rbt_merge_uniq( /*===========*/
ib_rbt_t* dst, /*!< in: dst rb tree */ const ib_rbt_t* src) /*!< in: src rb tree */
{
ib_rbt_bound_t parent;
ulint n_merged = 0; const ib_rbt_node_t* src_node = rbt_first(src);
if (rbt_empty(src) || dst == src) { return(0);
}
for (/* No op */; src_node; src_node = rbt_next(src, src_node)) {
#ifdefined UNIV_DEBUG || defined IB_RBT_TESTING /**********************************************************************//**
Check that every path from the root to the leaves has the same count and
the tree nodes are in order.
@returnTRUEif OK FALSE otherwise */
ibool
rbt_validate( /*=========*/ const ib_rbt_t* tree) /*!< in: RB tree to validate */
{ if (rbt_count_black_nodes(tree, ROOT(tree)) > 0) { return(rbt_check_ordering(tree));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.