红黑树的插入操作

Posted 涨点姿势吧

tags:

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

一,红黑树的五个性质:

1,每个结点为红色或者为黑色。

2,根结点为黑色

3,叶子结点为黑色

4,红色结点的两个儿子结点为黑色

5,对于每个结点,它的每条路径上有相同数目的黑色结点。

二,数据结构:

#define RED 0#define BLACK 1typedef int KEY_TYPE;typedef struct _rbtree_node{ unsigned char color; KEY_TYPE key; struct rbtree_node* left; struct rbtree_node* right; struct rbtree_node* parent;}rbtree_node;typedef struct _rbtree{ struct _rbtree_node* root; struct _rbtree_node* nil;}rbtree;

三、开始操作

我们假设插入结点为Z,红色,并将其插入到红黑树中了(先预设,当前结点Z的父结点为祖父结点的左孩子,那么当前结点Z的叔结点为祖父结点的右孩子)

现需要调整,调整有以下几种情况:

  • 父结点是黑色。(啥也不用管)

  • 父结点是红色(祖父节点肯定是黑色的,因为性质4)

    • 叔结点是红色的。此时需要变色。把父结点和叔结点都变为黑色。把祖父结点变为红色。继续判断祖父结点是否满足红黑树性质。

    • 叔结点是黑色的,此时需要判断,父结点需要不需要旋转。然后改变父结点的颜色为黑色、改变祖父结点的颜色为红色,旋转祖父结点。

一),父结点是黑色。

如下图,插入一个814结点,其父结点就是黑色的。满足红黑树性质。

二)、父结点是红色的,叔父结点也是红色的。调整时仅仅需要变色:

  • 当前节点:11

  • 当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色

红黑树的插入操作

  • (01) 将“父节点”设为黑色

  • (02) 将“叔叔节点”设为黑色

  • (03) 将“祖父节点”设为“红色

  • (04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作

红黑树的插入操作

三)、父结点是红色的,叔父结点是黑色的,调整分为两种:

第一种调整:

  • 当前节点:670

  • 当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子

红黑树的插入操作

  • (01) 将“父节点”设为“黑色”

  • (02) 将“祖父节点”设为“红色”

  • (03) 以“祖父节点”为支点进行右旋

红黑树的插入操作

第二种调整:

  • 当前节点:675

  • 当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子

  • (01) 将“父节点”作为“新的当前节点”

  • (02) 以“新的当前节点”为支点进行左旋

此时回到了第一种调整的样子,按照第一种调整方式来处理即可。

因此我们有以下思路:

1,插入结点Z到红黑树中,Z为当前结点,红色。

2,开始调整:当父结点是红色时

  • 如果父结点为祖父结点的左孩子

    • 叔结点为红色,变色处理。将父结点和叔结点变为黑色。把祖父结点变为红色。将祖父结点作为当前结点,继续循环2。

    • 叔结点为黑色,判断当前结点Z是父结点的左孩子还是右孩子

      • 如果是右孩子,则以父结点为中心左旋。变为 "长链  / "。

      • 改变父结点为黑色,祖父结点为红色。再以祖父结点为中心右旋。继续循环2。

  • 如果父结点为祖父结点的右孩子

    • 叔结点为红色,变色处理。将父结点和叔结点变为黑色。把祖父结点变为红色。将祖父结点作为当前结点,继续循环2.

    • 叔结点为红色,判断当前结点Z是父结点的左孩子还是右孩子,如果是左孩子,则以父结点为中心右旋,变为“长链  ”。

      • 改变父结点为黑色,祖父结点为红色。再以祖父结点为中心左旋。继续循环2。

代码如下:

void rbtree_insert_fixup(rbtree* T, rbtree_node* z){ //父结点为红色    while(z->parent->color == RED)                              { //父结点是祖父结点的左孩子 if(z->parent == z->parent->parent->left){  rbtree_node *y = z->parent->parent->right; //叔结点为红色,需要变色,然后将祖父结点作为当前结点,继续循环 if(y->color == RED){                 y->color = BLACK;                z->parent->color = BLACK;                z->parent->parent->color = RED;                z = z->parent->parent; }else{ //叔结点为黑色  if(z == z->parent->right){                    //当前结点是左孩子还是右孩子,如果是右孩子,需要先左旋,将其转化为"长链 /",                    //即祖父结点的左孩子是父节点,父结点的左孩子是当前结点 z = z->parent;                    rbtree_left_rotate(T,z); } //根据长链,变色,即改变父结点为黑色,祖父结点为红色,以祖父结点为中心,右旋。                z->parent->color = BLACK;                                      z->parent->parent->color = RED;                rbtree_right_rotate(T,z->parent->parent);            } }else{            rbtree_node* y = z->parent->parent->left;            if(y->color == RED) {                y->color->BLACK;                z->parent->color = BLACK;                z->parent->parent->color = RED;                z = z->parent->parent; }else{ if(z == z->parent->left){                    z = z->parent;                    rbtree_right_rotate(T,z);                }                z->parent->color = BLACK;                z->parent->parent->color = RED;                rbtree_left_rotate(T,z->parent->parent); }        }    }    T->root->color = BLACK;}void rbtree_insert_node(rbtree* T,rbtree_node* z){    rbtree_node* x = T->root;    rbtree_node* y = T->nil;     while(x!=T->nil){        y = x;        if(z->key < x->key) {            x = x->left; }else if(z->key > x->key){            x = x->right; }else{            return ;        }    }        z->parent = y; if(y == T->nil){ T->root = z; }else if(y->key > z->key){        y->left = z;  }else{ y->right = z; }
    z->color = RED;    z->left = T->nil;    z->right = T->nil;        rbtree_insert_fixup(T,z);}


以上是关于红黑树的插入操作的主要内容,如果未能解决你的问题,请参考以下文章

红黑树的插入与删除

红黑树介绍和结点的插入

红黑树:删除操作

红黑树

C++之红黑树

红黑树的插入操作过程详细图解