红黑树源码(含注释)

Posted 暗星涌动

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了红黑树源码(含注释)相关的知识,希望对你有一定的参考价值。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

typedef int key_t;

typedef enum color_t
{
   RED = 0,
   BLACK = 1
}color_t;

typedef struct rb_node_t
{
   struct rb_node_t *left, *right, *parent;
   key_t key;
   color_t color;
}rb_node_t;

rb_node_t* rb_insert(key_t key,  rb_node_t* root);
rb_node_t* rb_search(key_t key, rb_node_t* root);
rb_node_t* rb_erase(key_t key, rb_node_t* root);


// 打印
int  Print(key_t e )    
{
   printf("%d ", e );
   return 1;
}

// 中序遍历
int rb_print(rb_node_t* root,key_t(*Visit)(key_t))
{
 if(!root)
     return 0;
 else
 {
   if(root->left)
     rb_print(root->left,Visit);
   printf("%d ",root->key);
   if(root->right)
     rb_print(root->right,Visit);
 }
 return 1;
}


int main()
{
   int i, count = 10;
   key_t key;
   rb_node_t* root = NULL, *node = NULL;

// 随机插入元素    
   srand(time(NULL));
   for (i = 1; i < count; ++i)
   {
       key = rand() % count;  // key的值范围为 0 ~ 9
       if ((root = rb_insert(key, root)))
       {
           printf("[i = %d] insert key %d success!\n", i, key);
       }
       else
       {
           printf("[i = %d] insert key %d error!\n", i, key);
           exit(-1);
       }
// 打印树的中序遍历序列
       rb_print(root,Print);
       printf("\n");
   }

// 查找元素  
 key_t e;
 printf("The number e to be searched is: ");
 scanf("%d",&e);
 if ((node = rb_search(e, root)))
       printf("Have searched e !\n");
   else
       printf("Can not find e!\n");

// 删除元素    
 printf("The number e to be erased is: ");
   scanf("%d",&e);
 rb_erase(e, root);
       
   return 0;
}


// 结点的初始化
static rb_node_t* rb_new_node(key_t key)
{
   rb_node_t *node = (rb_node_t*)malloc(sizeof(struct rb_node_t));

   if (!node)  // 分配空间失败
   {
       printf("malloc error!\n");  
       exit(-1);
   }
   node->key = key;

   return node;
}

// 左旋调节
static rb_node_t* rb_rotate_left(rb_node_t* node, rb_node_t* root)
{
   rb_node_t* right = node->right;    // right 为 node 的右子结点

   if ((node->right = right->left))  // right 的左子节点转给 node 当右子结点
   {
       right->left->parent = node;    // 更改  right 的左子节点的父结点为 node
   }
   right->left = node;    // node 变成 right 的左子节点

   if ((right->parent = node->parent))    // right 的父结点改为 node 的父结点
   {
       if (node == node->parent->right)  // 如果 node 是 父结点的右支,right 替代 node
       {
           node->parent->right = right;  
       }
       else  // node 是父结点的左支
       {
           node->parent->left = right;
       }
   }
   else  // node 是根节点,则 right 变为根节点
   {
       root = right;
   }
   node->parent = right;  // node 的父结点改为其原右子结点

   return root;
}

// 右旋调节
static rb_node_t* rb_rotate_right(rb_node_t* node, rb_node_t* root)
{
   rb_node_t* left = node->left;  // 与左旋调节对称

   if ((node->left = left->right))
   {
       left->right->parent = node;
   }
   left->right = node;

   if ((left->parent = node->parent))
   {
       if (node == node->parent->right)
       {
           node->parent->right = left;
       }
       else
       {
           node->parent->left = left;
       }
   }
   else
   {
       root = left;
   }
   node->parent = left;

   return root;
}

// 插入元素后调节平衡
static rb_node_t* rb_insert_rebalance(rb_node_t *node, rb_node_t *root)
{
   rb_node_t *parent, *gparent, *uncle, *tmp;

   while ((parent = node->parent) && parent->color == RED)   //父结点为红色
   {
       gparent = parent->parent;  // 祖父节点

       if (parent == gparent->left)  // 父结点为祖父节点的左支
       {
           uncle = gparent->right;  
           if (uncle && uncle->color == RED)  // 叔结点也为红色
           {
               uncle->color = BLACK;  // 父结点和叔结点变为黑色,祖父节点变为红色
               parent->color = BLACK;
               gparent->color = RED;
               node = gparent;
           }
           else  // 叔结点为黑色
           {
               if (parent->right == node)  // 插入节点位于父结点的右支
               {
                   root = rb_rotate_left(parent, root);  // 左旋
                   tmp = parent;
                   parent = node;
                   node = tmp;    // 以父结点为支点再进行调整
               }

               parent->color = BLACK;  // 父结点改为黑色,祖父节点改为红色
               gparent->color = RED;
               root = rb_rotate_right(gparent, root);  // 右旋
           }
       }
       else  // 父结点为祖父节点的右支,调整与左支的对称
       {
           uncle = gparent->left;
           if (uncle && uncle->color == RED)
           {
               uncle->color = BLACK;
               parent->color = BLACK;
               gparent->color = RED;
               node = gparent;
           }
           else
           {
               if (parent->left == node)
               {
                   root = rb_rotate_right(parent, root);
                   tmp = parent;
                   parent = node;
                   node = tmp;
               }

               parent->color = BLACK;
               gparent->color = RED;
               root = rb_rotate_left(gparent, root);
           }
       }
   }

   root->color = BLACK;

   return root;
}

//删除元素的平衡
static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
{
   rb_node_t *other, *o_left, *o_right;

   while ((!node || node->color == BLACK) && node != root)  // 当前节点是黑色
   {
       if (parent->left == node)  // 当前节点位于父结点的左支
       {
           other = parent->right;  
           if (other->color == RED)  // 兄弟节点是红色
           {
               other->color = BLACK;  // 父结点和兄弟节点的颜色互换
               parent->color = RED;
               root = rb_rotate_left(parent, root);  // 左旋
               other = parent->right;
           }
           if ((!other->left || other->left->color == BLACK) &&(!other->right || other->right->color == BLACK)) // 兄弟节点的左右孩子为黑色
           {
               other->color = RED;  // 兄弟节点变为红色,父结点再进行一次平衡操作
               node = parent;
               parent = node->parent;
           }
           else
           {
               if (!other->right || other->right->color == BLACK)  // 只有兄弟节点的右孩子为黑色
               {
                   if ((o_left = other->left))  // 左孩子存在,则为红色
                   {
                       o_left->color = BLACK;  // 左孩子变为黑色
                   }
                   other->color = RED;  // 兄弟节点变为红色,以兄弟节点为支点右旋
                   root = rb_rotate_right(other, root);
                   other = parent->right;
               }
               other->color = parent->color;  // 父结点的颜色赋给兄弟节点,父结点变为黑色
               parent->color = BLACK;
               if (other->right)  // 兄弟节点的右孩子存在,则为红色
               {
                   other->right->color = BLACK;  // 兄弟节点的右孩子变为黑色
               }
               root = rb_rotate_left(parent, root);  // 左旋
               node = root;
               break;
           }
       }
       else  // 当前节点位于父结点的右支,调整过程与左支对称
       {
           other = parent->left;
           if (other->color == RED)
           {
               other->color = BLACK;
               parent->color = RED;
               root = rb_rotate_right(parent, root);
               other = parent->left;
           }
           if ((!other->left || other->left->color == BLACK) &&(!other->right || other->right->color == BLACK))
           {
               other->color = RED;
               node = parent;
               parent = node->parent;
           }
           else
           {
               if (!other->left || other->left->color == BLACK)
               {
                   if ((o_right = other->right))
                   {
                       o_right->color = BLACK;
                   }
                   other->color = RED;
                   root = rb_rotate_left(other, root);
                   other = parent->left;
               }
               other->color = parent->color;
               parent->color = BLACK;
               if (other->left)
               {
                   other->left->color = BLACK;
               }
               root = rb_rotate_right(parent, root);
               node = root;
               break;
           }
       }
   }

   if (node)
   {
       node->color = BLACK;
   }

   return root;
}

//查找元素
static rb_node_t* rb_search_auxiliary(key_t key, rb_node_t* root, rb_node_t** save)
{
   rb_node_t *node = root, *parent = NULL;
   int ret;

   while (node)
   {
       parent = node;
       ret = node->key - key;
       if (0 < ret)  // 结点的值比 key 值大,则从其左子树继续查找
       {
           node = node->left;
       }
       else if (0 > ret)  // 结点的值比 key 值小,则从其右子树继续查找
       {
           node = node->right;
       }
       else  // 找到 key 值
       {
           return node;
       }
   }

   if (save)
   {
       *save = parent;
   }

   return NULL;
}

//插入元素
rb_node_t* rb_insert(key_t key, rb_node_t* root)
{
   rb_node_t *parent = NULL, *node;

   parent = NULL;
   if ((node = rb_search_auxiliary(key, root, &parent)))  // 树中已有该元素,则不再插入
   {
       return root;
   }

   node = rb_new_node(key);  // 给结点赋值,并初始化其颜色为红色
   node->parent = parent;
   node->left = node->right = NULL;
   node->color = RED;

   if (parent)  // 选择插入到左支还是右支
   {
       if (parent->key > key)
       {
           parent->left = node;
       }
       else
       {
           parent->right = node;
       }
   }
   else  // 该节点为根节点
   {
       root = node;
   }

   return rb_insert_rebalance(node, root);
}

//查找元素
rb_node_t* rb_search(key_t key, rb_node_t* root)
{
   return rb_search_auxiliary(key, root, NULL);
}

//删除元素
rb_node_t* rb_erase(key_t key, rb_node_t *root)
{
   rb_node_t *child, *parent, *old, *left, *node;
   color_t color;

   if (!(node = rb_search_auxiliary(key, root, NULL)))
   {
       printf("e is not exist!\n");  // 没有找到该元素
       return root;
   }

   old = node;

   if (node->left && node->right)  // 被删除结点左右子树存在
   {
       node = node->right;
       while ((left = node->left) != NULL)  // 寻找当前节点,即被删除结点的中序后继结点
       {
           node = left;
       }
       child = node->right;
       parent = node->parent;
       color = node->color;

       if (child)
       {
           child->parent = parent;
       }
       if (parent)
       {
           if (parent->left == node)  // 当前节点在左支
           {
               parent->left = child;
           }
           else  // 当前节点在右支
           {
               parent->right = child;
           }
       }
       else  
       {
           root = child;
       }

       if (node->parent == old)
       {
           parent = node;
       }

       node->parent = old->parent;   // 当前节点和根节点互换
       node->color = old->color;
       node->right = old->right;
       node->left = old->left;

       if (old->parent)
       {
           if (old->parent->left == old)  // 被删除结点在左支
           {
               old->parent->left = node;
           }
           else  // 被删除结点在右支
           {
               old->parent->right = node;
           }
       }
       else  // 被删除结点为根节点
       {
           root = node;
       }

       old->left->parent = node;   // 连接当前节点和被删除结点的子树
       if (old->right)
       {
           old->right->parent = node;
       }
   }
   else
   {
       if (!node->left)  // 左子树不存在
       {
           child = node->right;
       }
       else if (!node->right)  // 右子树不存在
       {
           child = node->left;
       }
       parent = node->parent;
       color = node->color;

       if (child)
       {
           child->parent = parent;  // 替代被删除结点
       }
       if (parent)
       {
           if (parent->left == node)  // 左支
           {
               parent->left = child;
           }
           else  // 右支
           {
               parent->right = child;  
           }
       }
       else  // 根节点
       {
           root = child;
       }
   }

   free(old);

   if (color == BLACK)
   {
       root = rb_erase_rebalance(child, parent, root);
   }
   
//打印删除后的中序遍历序列    
   printf("after deleting : ");
   rb_print(root,Print);
   printf("\n");

   return root;
}


以上是关于红黑树源码(含注释)的主要内容,如果未能解决你的问题,请参考以下文章

HashMap红黑树原理及源码分析---图形注释一应俱全

红黑树的C实现完整源码

jdk8 HashMap 源码解析-红黑树

HashMap底层红黑树原理(超详细图解)+手写红黑树代码

算法手撕红黑树(下)—— 一张流程图梳理删除操作(含实现代码)

STL 红黑树源码分析