紅黑樹及C語言實現

紅黑樹與C語言查找算法

    紅黑樹是一種自平衡二叉查找樹,是在計算機科學中用到的一種數據結構,典型的用途是實現關聯數組。它是在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                                                            *
* 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.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);
}


測試文件:

//
// 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;
}

轉自:http://blog.csdn.net/cheungmine/archive/2010/11/16/6012061.aspx
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章