/* * red_black.h */ #ifndef _RED_BLACK_H #define _RED_BLACK_H typedef enum _color_t { RED, BLACK }color_t; typedef struct _red_black_t { int data; color_t color; struct _red_black_t *parent; struct _red_black_t *left; struct _red_black_t *right; }red_black_t; extern int init_rbt(red_black_t **root, int value); extern void delete_rbt(red_black_t *root); extern red_black_t* rbt_insert(red_black_t *root, int value); extern int rbt_delete(red_black_t **root, int value); extern void rbt_print_preorder(red_black_t *root); extern red_black_t* rbt_search(red_black_t *root, int value); extern int rbt_get_height(red_black_t *root); #endif /* * red_black.c */ /* * 红黑树性质: * 1. 每个结点或红或黑。 * 2. 根结点为黑色。 * 3. 每个叶结点(实际上就是NULL指针)都是黑色的。 * 4. 如果一个结点是红色的,那么它的周边3个节点都是黑色的。 * 5. 对于每个结点,从该结点到其所有子孙叶结点的路径中所包含的黑色结点个数都一样。 */ #include <stdio.h> #include <stdlib.h> #include "red_black.h" static red_black_t* rbt_rebalance(red_black_t *root, red_black_t *node); static red_black_t* rbt_rotate_right(red_black_t *root, red_black_t *node); static red_black_t* rbt_rotate_left(red_black_t *root, red_black_t *node); static red_black_t* rbt_delete_node(red_black_t *root, red_black_t *node); static int rbt_height(red_black_t *root); int init_rbt(red_black_t **root, int value) { if((*root = (red_black_t *)malloc(sizeof(red_black_t))) == NULL) { return -1; } (*root)->data = value; (*root)->color = BLACK; (*root)->parent = NULL; (*root)->left = NULL; (*root)->right = NULL; return 0; } void delete_rbt(red_black_t *root) { if(root) { delete_rbt(root->left); delete_rbt(root->right); free(root); } } /* * 插入操作:解决的是 红-红 问题 */ red_black_t* rbt_insert(red_black_t *root, int value) { red_black_t *node = (red_black_t *)malloc(sizeof(red_black_t)); red_black_t *parent; red_black_t *cur; if(node) { node->data = value; node->color = RED; node->parent = NULL; node->left = NULL; node->right = NULL; /* find parent node */ cur = root; parent = root; while(cur) { parent = cur; if(cur->data > value) { cur = cur->left; } else if(cur->data < value) { cur = cur->right; } else { return root; } } /* insert node */ node->parent = parent; if(parent) { if(parent->data > value) { parent->left = node; } else { parent->right = node; } } else { root = node; } root = rbt_rebalance(root, node); } return root; } /* * 1. 红黑树的插入和普通搜索二叉树(Binary Search Tree)的插入一样, * 只是在插入完以后,将新插入的节点标记为红色,然后从该节点开始,向上进行调整颜色。 * 2. 向上调整颜色进行旋转时,旋转的原则是尽量用1次或者最多2次旋转完成, * 并且旋转操作不能影响该层以下层次的节点,只能影响其父节点, * 然后将其父节点(或者叔节点、兄弟节点)作为新的要调整颜色节点,继续向上递推调整。 * 3. 调整完后注意检查根的颜色是否还是黑色。 */ static red_black_t* rbt_rebalance(red_black_t *root, red_black_t *node) { red_black_t *parent = NULL; red_black_t *uncle = NULL; red_black_t *ancestor = NULL; red_black_t *tmp = NULL; while(((parent=node->parent) != NULL) && (parent->color == RED)) { ancestor = parent->parent; /* parent 为红色, ancestor 一定为黑色 */ if(parent == ancestor->left) { uncle = ancestor->right; if(uncle && uncle->color == RED) { /* parent 和 uncle 均为红色, 只需修改颜色 */ uncle->color = BLACK; parent->color = BLACK; ancestor->color = RED; node = ancestor; } else { /* 旋转 */ if(parent->right == node) { /* 先左旋 */ /*----------------------------------------------------------- | bast bast | / / / / | rprt buce ==> rnode buce | / / / / | ba rnode rprt bc | / / / / | bb bc ba bb -----------------------------------------------------------*/ root = rbt_rotate_left(root, parent); tmp = parent; parent = node; node = tmp; } /*----------------------------------------------------------- | bast rprt bprt | / / / / / / | rprt buce ==> rnode bast ==> rnode rast | / / / / / / / / / / | rnode bc ba bb bc buce ba bb bc buce | / / | ba bb -----------------------------------------------------------*/ ancestor->color = RED; parent->color = BLACK; root = rbt_rotate_right(root, ancestor); } } else { /* 思路与 if 一样 */ uncle = ancestor->left; if(uncle && uncle->color == RED) { /* parent 和 uncle 均为红色, 只需修改颜色 */ uncle->color = BLACK; parent->color = BLACK; ancestor->color = RED; node = ancestor; } else { /* 旋转 */ if(parent->left == node) { /* 先左旋 */ /*----------------------------------------------------------- | bast bast | / / / / | buce rprt ==> buce rnode | / / / / | rnode bc ba rprt | / / / / | ba bb bb bc -----------------------------------------------------------*/ root = rbt_rotate_right(root, parent); tmp = parent; parent = node; node = tmp; } /*----------------------------------------------------------- | bast rprt bprt | / / / / / / | buce rprt ==> bast rnode ==> rast rnode | / / / / / / / / / / | ba rnode buce ba bb bc buce ba bb bc | / / | bb bc -----------------------------------------------------------*/ ancestor->color = RED; parent->color = BLACK; root = rbt_rotate_left(root, ancestor); } } } /* 上述过程有可能修改了 root 节点 */ root->color = BLACK; return root; } int rbt_delete(red_black_t **root, int value) { red_black_t *tmp; if((tmp=rbt_search(*root, value)) != NULL) { *root = rbt_delete_node(*root, tmp); } return 0; } /* * 删除操作:解决的是 黑-黑 问题 * * * 删除操作思路来自 二叉排序树 * 删除的节点都表示成实际要删除的中序遍历的后继节点 * 那么要删除的节点的左子树一定为空, 由红黑树高度可知: * 如果删除的节点为红色,那么它必为叶子节点 * 如果删除的节点为黑色, 删除的节点要么有一个右孩子,要么为叶子节点. */ static red_black_t* rbt_delete_node(red_black_t *root, red_black_t *node) { red_black_t *tmp = NULL; if(node->right == NULL) { /* 要删除的节点只有左孩子或者没有孩子 */ if(node->parent == NULL) { /* 删除根节点 */ root = node->left; if(root) { root->color = BLACK; } } else if(node->parent->left == node) { node->parent->left = node->left; } else { node->parent->right = node->left; } /* 更新孩子父亲 */ if(node->left) { node->left->parent = node->parent; } tmp = node->left; } else { /* 找到 root->right 的最左儿子代替 root, 换成删除叶子节点或只有右孩子的节点 tmp */ tmp = node->right; while(tmp->left) { tmp = tmp->left; } node->data = tmp->data; /* 将要删除的节点赋给 node */ node = tmp; if(node->parent->left == node) { node->parent->left = node->right; } else { node->parent->right = node->right; } if(node->right) { /* 右子树非空 */ node->right->parent = node->parent; } tmp = node->right; } if(node->color == BLACK && tmp) { /* 删除节点的颜色为黑色且子树不为空时调整 */ root = rbt_rebalance(root, tmp); } free(node); return root; } /*----------------------------------------------------------- | node tmp | / / / / | tmp y ==> a node | / / / / | a b b y -----------------------------------------------------------*/ /* 只旋转, 不改变颜色 */ static red_black_t* rbt_rotate_right(red_black_t *root, red_black_t *node) { red_black_t *tmp = node->left; if((tmp->parent=node->parent) == NULL) { root = tmp; } else { /* 修改 node 的 parent 节点的孩子指针 */ if(node->parent->left == node) { node->parent->left = tmp; } else { node->parent->right = tmp; } } node->parent = tmp; node->left = tmp->right; if(tmp->right) { tmp->right->parent = node; } tmp->right = node; return root; } /*----------------------------------------------------------- | node tmp | / / ==> / / | a tmp node y | / / / / | b y a b -----------------------------------------------------------*/ /* 只旋转, 不改变颜色 */ static red_black_t* rbt_rotate_left(red_black_t *root, red_black_t *node) { red_black_t *tmp = node->right; if((tmp->parent=node->parent) == NULL) { root = tmp; } else { /* 修改 node 的 parent 节点的孩子指针 */ if(node->parent->left == node) { node->parent->left = tmp; } else { node->parent->right = tmp; } } node->parent = tmp; node->right = tmp->left; if(tmp->left) { tmp->left->parent = node; } tmp->left = node; return root; } void rbt_print_preorder(red_black_t *root) { if(root) { printf("%d [color: %s] ", root->data, (root->color == RED ? "RED" : "BLACK")); if(root->parent) { printf("[parent: %d] ", root->parent->data); } if(root->left) { printf("[left: %d] ", root->left->data); } if(root->right) { printf("[right: %d] ", root->right->data); } printf("/n"); rbt_print_preorder(root->left); rbt_print_preorder(root->right); } } red_black_t* rbt_search(red_black_t *root, int value) { red_black_t *cur = root; while(cur) { if(cur->data == value) { break; } else if(cur->data > value) { cur = cur->left; } else { cur = cur->right; } } return cur; } /* * 高度是指黑节点个数 */ int rbt_get_height(red_black_t *root) { int ret = 0; if(root) { ret = rbt_height(root); } return ret; } int rbt_height(red_black_t *root) { int ret = 1; /* 每个叶结点(实际上就是NULL指针)都是黑色的 */ int left = 0; int right = 0; if(root) { left = rbt_height(root->left); right = rbt_height(root->right); ret = (left >= right ? left : right) + 1; if(root->color == RED) { ret--; } } return ret; } void rbt_test_app(void) { int s, v; red_black_t *root = NULL; init_rbt(&root, 19); while(1) { printf("/n******************************/n"); printf("0: exit/n"); printf("1: print/n"); printf("2: find/n"); printf("3: depth/n"); printf("4: insert/n"); printf("5: delete/n"); printf("******************************/n"); printf("select: "); scanf("%d", &s); if(s == 0) { delete_rbt(root); return; } else if(s == 1) { rbt_print_preorder(root); } else if(s == 2 || s == 4 || s == 5) { printf("value: "); scanf("%d", &v); if(rbt_search(root, v) == NULL) { if(s == 4) { root = rbt_insert(root, v); } else if(s == 5) { printf("not exists fail delete/n"); } else { printf("not exists/n"); } } else { if(s == 5) { if(!rbt_delete(&root, v)) { printf("deleted/n"); } else { printf("fail delete/n"); } } else { printf("already exists/n"); } } } else if(s == 3) { printf("height: %d/n", rbt_height(root)); } } }