标签:
红黑树是一种二叉平衡树,在每一个结点增加了一个存储位表示结点的颜色,以维持它的平衡;
(1)红黑树结点有如下域:color,key,left,right,p;我们把这些NIL结点是为指向外结点的指针,可以自己定义;
(2)每一个结点不是红的就是黑的,根节点和NIL结点都是黑的;
(3)如果一个节点是红的,那么它的父亲和两个孩子都是黑的;
(4)对于每一个结点,它到其子孙结点的所有路径上的包含相同数目的black结点,并不要求父节点到每一层的黑高度相同;
注1:可以使用同一的一个NIL来表示所有的叶子结点和根部的父节点,这样可以减少浪费内存,该NIL的父亲就是上述的普通结点,这样查找不成功时,就可以重新回到根节点root;
注2:设某个结点x出发到达任意一个节点的任意路径上,黑结点的个数称为该节点的黑高度,bh(x)表示;可归纳证明出根节点至少有2^h-1个结点,故n>=2^h-1,求得h<=2lg(n+1);
(2)若刚开始树为空,则z是根节点,p为NIL节点,则将z的结点改为黑色;
(3)若p的颜色是黑色,则直接插入,因为红黑树的性质完全保持;
(4)若p的颜色是红色,违反红黑树的性质3,此时要讨论情况;
(4.1)若p是p父亲的左孩子;
(4.1.1)若p的兄弟节点ps是红色,则改变p和ps为黑色,p父节点改为红色,此时p父节点为新的z,继续判别;
(4.1.2)若p的兄弟节点ps是黑色,且z是父亲的右孩子,做一次左旋,到情况(4.1.3);
(4.1.3)若p的兄弟节点ps是黑色,且z是父亲的左孩子,做一次右旋,改变z父亲颜色为黑色,z祖父颜色为红色,完毕;
(4.2)若p是p父亲的右孩子;情况与(4.1)类似,执行相反的动作;
(5)始终将根节点的颜色置为黑,因为处理时根节点有可能变红;
(6)时间复杂度为O(lgn),空间复杂度为O(1);
(2)若y为红色,直接删掉,因为红黑树的性质保持不变;
(3)若y为黑色节点,x为红色,则直接删掉y,将x变为黑色;
(4)若y为黑色节点,x(可以为NIl节点)为黑色,则删掉y,将x变为双黑色;
(4.1)若x是x父亲的左孩子,分别有四种情况来讨论;
(4.1.1)若x的兄弟是红色,则左旋一次,改变兄弟颜色为黑,父亲颜色为红,则它仍为新的x,继续;
(4.1.2)若x的兄弟是黑色,且x兄弟的两个孩子都是黑色,则去掉x的一重黑色,将兄弟颜色变为红,将去掉的一重黑色,给x的父亲,若x父亲是红色,则直接改成黑色,否则将变成双黑,成为新的x,继续;
(4.1.3)若x的兄弟是黑色,且x兄弟的右孩子黑色,左孩子是红色,则先将x兄弟那一块右旋,改色,使得x兄弟的右孩子变为红色;进入(4.1.4);
(4.1.4)若x的兄弟是黑色,且x兄弟的右孩子红色,左孩子可任意色,则左旋,改变x兄弟右孩子颜色为黑色,兄弟变为父亲的颜色,父亲变为黑色,自己去掉一重颜色,完毕;
(4.2)若x是x父亲的右孩子,分别也有四种情况来讨论,但与(4.1)对称,相反来处理;
(5)若根为双黑,直接变为单黑,返回;
(6)时间复杂度为O(lgn),空间复杂度为O(1);
(本节代码取自nginx中红黑树相关的代码)
typedef struct ngx_rbtree_node_s ngx_rbtree_node_t; //红黑树节点的定义 struct ngx_rbtree_node_s { ngx_rbtree_key_t key; //关键字 ngx_rbtree_node_t *left; //左子节点 ngx_rbtree_node_t *right; //右子节点 ngx_rbtree_node_t *parent;//父节点 u_char color; //颜色,非红即黑 u_char data; //1个字节的节点数据,空间较小很少使用; }; typedef struct ngx_rbtree_s ngx_rbtree_t; //为解决不同节点含有相同关键字元素冲突问题,设置该指针,灵活的添加冲突元素 typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); //红黑树的定义 struct ngx_rbtree_s { ngx_rbtree_node_t *root; //指向树的根节点,根结点也是数据元素 ngx_rbtree_node_t *sentinel; //指向哨兵NIL节点 ngx_rbtree_insert_pt insert; //添加元素的函数指针 };
//颜色设置 #define ngx_rbt_red(node) ((node)->color = 1) #define ngx_rbt_black(node) ((node)->color = 0) #define ngx_rbt_is_red(node) ((node)->color) #define ngx_rbt_is_black(node) (!ngx_rbt_is_red(node)) #define ngx_rbt_copy_color(n1, n2) (n1->color = n2->color)
//内联函数,寻找值最小的节点 static ngx_inline ngx_rbtree_node_t * ngx_rbtree_min(ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { while (node->left != sentinel) { node = node->left; } return node; }
#define ngx_rbtree_init(tree, s, i) ngx_rbtree_sentinel_init(s); (tree)->root = s; (tree)->sentinel = s; (tree)->insert = i
其中tree代表红黑树管理结构,s代表NIL节点,i代表添加元素的函数;
/* a sentinel must be black */ #define ngx_rbtree_sentinel_init(node) ngx_rbt_black(node)
//左旋转 static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node) { ngx_rbtree_node_t *temp; temp = node->right; //要旋转节点的右孩子p node->right = temp->left; //当前节点的右孩子指向改变p的左孩子 if (temp->left != sentinel) { //不是NIL节点时 temp->left->parent = node; //修改父亲的指向 } temp->parent = node->parent; //p指向要旋转节点的父亲 if (node == *root) { //如果当前旋转节点的是根结点,那么根指向要改变 *root = temp; } else if (node == node->parent->left) { //左孩子时 node->parent->left = temp; //新的左孩子 } else { node->parent->right = temp; //新的右孩子 } temp->left = node; //p的左孩子指向 node->parent = temp; //父亲改变 } //右旋转,与上述左边旋转对称 static ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node) { ngx_rbtree_node_t *temp; temp = node->left; node->left = temp->right; if (temp->right != sentinel) { temp->right->parent = node; } temp->parent = node->parent; if (node == *root) { *root = temp; } else if (node == node->parent->right) { node->parent->right = temp; } else { node->parent->left = temp; } temp->right = node; node->parent = temp; }
void ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) { //temp为初始时为指向根节点 ngx_rbtree_node_t **p; for ( ;; ) { p = (node->key < temp->key) ? &temp->left : &temp->right; //目标节点的值小于当前节点的值时,向左走即走向左节点,否则向右 if (*p == sentinel) { //一直找到该节点的孩子指向的是NIL节点,直接break break; } temp = *p; //改变方向 } //注意使用地址的地址,才能改变某节点的孩子的指向,否则改变不了 *p = node; //该处指向新的节点,*p(某节点的孩子)本来指向sentinel,现在指向node了 node->parent = temp; node->left = sentinel; //指向NIL node->right = sentinel; ngx_rbt_red(node); //插入的节点均为红色 }
void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node) { ngx_rbtree_node_t **root, *temp, *sentinel; /* a binary tree insert */ root = (ngx_rbtree_node_t **) &tree->root; //指向根节点指针的指针,可改变指向根节点指针的指向 sentinel = tree->sentinel; //取出NIL节点 if (*root == sentinel) { //说明此时红黑树为空 node->parent = NULL; node->left = sentinel; //指向NIL node->right = sentinel; ngx_rbt_black(node); //node节点直接置为黑 *root = node; //根节点直接指向该节点 return; } tree->insert(*root, node, sentinel); //插入节点,如ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) /* re-balance tree */ //红黑树平衡 //当前节点不为根节点,而且当前节点的父亲为红色时 while (node != *root && ngx_rbt_is_red(node->parent)) { if (node->parent == node->parent->parent->left) { //当前节点的父亲是左节点时 temp = node->parent->parent->right; //当前节点的父亲的右兄弟 //向上转移 if (ngx_rbt_is_red(temp)) { //对应算法导论第三版P179的情况1 ngx_rbt_black(node->parent); //当前节点的父亲变黑 ngx_rbt_black(temp); //当前节点的父亲的右兄弟变黑 ngx_rbt_red(node->parent->parent);//当前节点的父亲的父亲变红 node = node->parent->parent; //当前节点变为该当前节点的父亲的父亲 } else { //当前节点的父亲的右兄弟为黑色时 //对应算法导论第三版P179的情况2 //当前节点是右节点时,先左旋转 if (node == node->parent->right) { node = node->parent; //当节点变为父节点 ngx_rbtree_left_rotate(root, sentinel, node); //当前节点左旋转 } //对应算法导论第三版P179的情况3 ngx_rbt_black(node->parent); //当前节点的父亲变为黑色 ngx_rbt_red(node->parent->parent); //当前节点的父亲的父亲变为黑色 ngx_rbtree_right_rotate(root, sentinel, node->parent->parent); //当前节点父亲的父亲右旋转 } } else { //相反,对称操作 temp = node->parent->parent->left; if (ngx_rbt_is_red(temp)) { ngx_rbt_black(node->parent); ngx_rbt_black(temp); ngx_rbt_red(node->parent->parent); node = node->parent->parent; } else { if (node == node->parent->left) { node = node->parent; ngx_rbtree_right_rotate(root, sentinel, node); } ngx_rbt_black(node->parent); ngx_rbt_red(node->parent->parent); ngx_rbtree_left_rotate(root, sentinel, node->parent->parent); } } } ngx_rbt_black(*root); //最后始终着色根结点为黑色 }
void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node) { ngx_uint_t red; ngx_rbtree_node_t **root, *sentinel, *subst, *temp, *w; /* a binary tree delete */ root = (ngx_rbtree_node_t **) &tree->root; sentinel = tree->sentinel; //subst为要替代的节点 //temp为将要替代节点的孩子 if (node->left == sentinel) { //删除节点为左孩子为NIL节点 temp = node->right; subst = node; } else if (node->right == sentinel) { temp = node->left; subst = node; } else { subst = ngx_rbtree_min(node->right, sentinel); //找到以删除节点右孩子为根的最小值节点 if (subst->left != sentinel) { temp = subst->left; } else { //通过ngx_rbtree_min找到的,该最小值节点的左孩子一定是NIL temp = subst->right; } } if (subst == *root) { //subst为要删除的节点为根节点时 *root = temp; //指向新的根节点 ngx_rbt_black(temp); /* DEBUG stuff */ node->left = NULL; node->right = NULL; node->parent = NULL; node->key = 0; return; } red = ngx_rbt_is_red(subst); //直接取颜色 if (subst == subst->parent->left) { subst->parent->left = temp; //父亲的左孩子指向要删除节点的左孩子 } else { subst->parent->right = temp; //父亲的右孩子指向要删除节点的右孩子 } if (subst == node) { //要删除的节点为原始的节点时 temp->parent = subst->parent; //父亲节点指向的改变 } else { if (subst->parent == node) { //通过ngx_rbtree_min一开始就不成立,即node->right的left为NIL节点 temp->parent = subst; } else { temp->parent = subst->parent; //通过ngx_rbtree_min找到的 } subst->left = node->left; //指向node的左孩子 subst->right = node->right; //指向node的右孩子 subst->parent = node->parent; ngx_rbt_copy_color(subst, node); //将node节点的颜色复制给subst节点 if (node == *root) { *root = subst; //指向新的根节点 } else { if (node == node->parent->left) { node->parent->left = subst; //改变父亲孩子指向到subst } else { node->parent->right = subst; } } if (subst->left != sentinel) { //改变subst孩子的指向 subst->left->parent = subst; } if (subst->right != sentinel) { subst->right->parent = subst; } } /* DEBUG stuff */ node->left = NULL; node->right = NULL; node->parent = NULL; node->key = 0; if (red) { //如果删除的节点的颜色为红色,直接返回 return; } //平衡 /* a delete fixup */ //孩子节点,如果孩子节点为黑色时 while (temp != *root && ngx_rbt_is_black(temp)) { if (temp == temp->parent->left) { //temp为左孩子时 w = temp->parent->right; //temp的右兄弟 //算法导论第三版P186中的情况a if (ngx_rbt_is_red(w)) { //temp的右兄弟为红色时 ngx_rbt_black(w); //temp的右兄弟变为黑色 ngx_rbt_red(temp->parent); //temp的父亲变为红色色 ngx_rbtree_left_rotate(root, sentinel, temp->parent); //以temp->parent左旋转 w = temp->parent->right; //新的右兄弟,将会到以下几种情况 } //算法导论第三版P186中的情况b //当temp的右兄弟的两个孩子均为黑色时 if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) { ngx_rbt_red(w); //将右兄弟变为红色 temp = temp->parent; //将以新的temp进行新的一次循环 } else { //算法导论第三版P186中的情况c if (ngx_rbt_is_black(w->right)) { //如果右兄弟的右孩子是黑色的 ngx_rbt_black(w->left); //w的左孩子变黑 ngx_rbt_red(w); //w变红 ngx_rbtree_right_rotate(root, sentinel, w); //以w右旋 w = temp->parent->right; //新的右兄弟,直接执行情况c } //算法导论第三版P186中的情况d ngx_rbt_copy_color(w, temp->parent); //右兄弟变成父亲的颜色 ngx_rbt_black(temp->parent); //temp的父亲变黑 ngx_rbt_black(w->right); //右兄弟的右孩子变黑 ngx_rbtree_left_rotate(root, sentinel, temp->parent); //以temp的父亲右旋 temp = *root; //结束,直接指向根结点 } } else { //与上述情况相反,做对称操作 w = temp->parent->left; if (ngx_rbt_is_red(w)) { ngx_rbt_black(w); ngx_rbt_red(temp->parent); ngx_rbtree_right_rotate(root, sentinel, temp->parent); w = temp->parent->left; } if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) { ngx_rbt_red(w); temp = temp->parent; } else { if (ngx_rbt_is_black(w->left)) { ngx_rbt_black(w->right); ngx_rbt_red(w); ngx_rbtree_left_rotate(root, sentinel, w); w = temp->parent->left; } ngx_rbt_copy_color(w, temp->parent); ngx_rbt_black(temp->parent); ngx_rbt_black(w->left); ngx_rbtree_right_rotate(root, sentinel, temp->parent); temp = *root; } } } //temp为红色时,直接将temp置为黑色 ngx_rbt_black(temp); }
标签:
原文地址:http://blog.csdn.net/skyuppour/article/details/45769031