红黑树

https://blog.csdn.net/very_2/article/details/5722682


二叉树可视化--Graphviz

https://blog.csdn.net/hackooo/article/details/10564049

/*==================================

*  Copyright (C) 2016 All rights reserved.

*  文件名称:rbt.c


*  描    述:红黑树实现

*

================================================================*/

#include

#include

#include

#define RB_RED 0

#define RB_BLACK 1

typedef struct rb_node

{

    struct rb_node* left;

    struct rb_node* right;

    struct rb_node* parent;

    uint32_t color:1;

    uint32_t data:31;

} rb_node;

typedef struct rb_tree

{

    rb_node* root;

} rb_tree;

static inline void rb_init(rb_tree* tree)

{

    tree->root = NULL;

}

static inline void rb_init_node(rb_node* node)

{

    node->color = RB_RED;

    node->parent = node->left = node->right = NULL;

}

static inline void rb_draw_begin(FILE* fp)

{

    fprintf(fp, "digraph G{\n");

}

static inline void rb_draw_end(FILE* fp)

{

    fprintf(fp, "}\n");

}

#define rb_draw_debug(node, tree) __rb_draw_debug(node, tree, __LINE__)

void __rb_draw_debug(rb_node* node, rb_tree* tree, int line);

void rb_draw_tree(FILE* fp, rb_node* node);

void rb_draw(rb_node* node, const char* filename);

void rb_insert(rb_tree* tree, rb_node* node);

void rb_rotate_right(rb_node* node)

{

    rb_node* p = node->parent;

    rb_node* l = node->left;

    rb_node* lr = l->right;

    l->right = node;

    node->parent = l;

    node->left = lr;

    if(lr) lr->parent = node;

    l->parent = p;

    if(p)

    {

        if(p->left == node) p->left = l;

        else p->right = l;

    }

}

void rb_rotate_left(rb_node* node)

{

    rb_node* p = node->parent;

    rb_node* r = node->right;

    rb_node* rl = r->left;

    r->left = node;

    node->parent = r;

    node->right = rl;

    if(rl) rl->parent = node;

    r->parent = p;

    if(p)

    {

        if(p->left == node) p->left = r;

        else p->right = r;

    }

}

void rb_insert_adjust(rb_tree* tree, rb_node* node)

{

    if(node->parent == NULL)

    {

        node->color = RB_BLACK;

        tree->root = node;

        return;

    }

    if(node->color == RB_BLACK || node->parent->color == RB_BLACK)

        return;

    rb_node* uncle = NULL;

    rb_node* parent = node->parent;

    rb_node* grand = parent->parent;

    if(grand->left == parent)

        uncle = grand->right;

    else

        uncle = grand->left;

    if(uncle && uncle->color == RB_RED)

    {

        uncle->color = RB_BLACK;

        parent->color = RB_BLACK;

        grand->color = RB_RED;

        rb_insert_adjust(tree, grand);

        return;

    }

    if(grand->left == parent && parent->left == node)

    {

        rb_rotate_right(grand);

        grand->color = RB_RED;

        parent->color = RB_BLACK;

        rb_insert_adjust(tree, parent);

    }

    else if(grand->right == parent && parent->right == node)

    {

        rb_rotate_left(grand);

        grand->color = RB_RED;

        parent->color = RB_BLACK;

        rb_insert_adjust(tree, parent);

    }

    else if(grand->left == parent && parent->right == node)

    {

        rb_rotate_left(parent);

        rb_insert_adjust(tree, parent);

    }

    else if(grand->right == parent && parent->left == node)

    {

        rb_rotate_right(parent);

        rb_insert_adjust(tree, parent);

    }

}

void rb_insert(rb_tree *tree, rb_node *node)

{

    rb_init_node(node);

    if(tree->root == NULL)

    {

        tree->root = node;

        node->color = RB_BLACK;

        return;

    }

    rb_node* parent = tree->root;

    while(1)

    {

        if(node->data < parent->data)

        {

            // left

            if(parent->left)

            {

                parent = parent->left;

            }

            else

            {

                parent->left = node;

                node->parent = parent;

                break;

            }

        }

        else

        {

            if(parent->right)

            {

                parent = parent->right;

            }

            else

            {

                parent->right = node;

                node->parent = parent;

                break;

            }

        }

    }

    rb_insert_adjust(tree, node);

}

void rb_draw_tree(FILE* fp, rb_node* node)

{

    if(node == NULL)

        return;

    if(node->color == RB_BLACK)

        fprintf(fp, "node[shape=record,style=filled,color=black,fontcolor=white];\n");

    else

        fprintf(fp, "node[shape=record,style=filled,color=red,fontcolor=white];\n");

    fprintf(fp, "%d[label=\" | %d | \"];\n", node->data, node->data);

    rb_node* parent = node->parent;

    if(parent)

    {

        if(parent->left == node)

        {

            fprintf(fp, "%d:f0:sw->%d:f1;\n", parent->data, node->data);

        }

        else

        {

            fprintf(fp, "%d:f2:se->%d:f1;\n", parent->data, node->data);

        }

    }

    rb_draw_tree(fp, node->left);

    rb_draw_tree(fp, node->right);

}

void __rb_draw_debug(rb_node* node, rb_tree* tree, int line)

{

    static int v = 0;

    char buf[256];

    sprintf(buf, "%d_%d_%d.dot",v++, node->data,  line);

  //  rb_draw(tree->root, buf);

}

void rb_draw(rb_node* root, const char* filename)

{

    FILE* fp = fopen(filename, "w");

    rb_draw_begin(fp);

    rb_draw_tree(fp, root);

    rb_draw_end(fp);

    fclose(fp);

    char cmd[1024];

    sprintf(cmd, "dot %s -Tpng -o %s.png", filename, filename);

    //"dot example1.dot –Tpng –o example1.png"

    popen(cmd, "r");

}

/* 删除节点:

* 删除节点时,首先需要将被删除的节点替换到底层

* 替换到底层之后,被删除的节点,要么只有一个儿子,要么没有儿子,不可能存在两个儿子的情况

* 1. 没有儿子

* 1.1 该节点是红色节点:直接删除,太开心了

* 1.2 该节点是黑色节点:太闹心了,见下面吧

* 2. 有一个儿子

* 这个简单,这个儿子一定是红色的,交换一下删除就是了

*

* 考虑这个情况:被删除的节点是黑色的,而且没有儿子

* 这种情况下,将该节点直接删除,然后以它原来的父亲节点为“参考节点”

* 这种情况下,删除叶子节点破坏了红黑树的平衡性,做法的目的是,在这个方向上给它补充一个黑色节点

*

* 理论:当以参考节点的父亲节点为根节点的子树,如果可以再次平衡,并且补充了被删除的黑色节点之后,整个树还是平衡的

* 1. 红色的兄弟

*    在这种情况下,父亲一定是黑色的,这种情况很简单,以父亲做一次旋转(左还是右,则看兄弟位置),然后将兄弟变成黑色,父亲变成红色,删除立马变得简单

*

* 2. 黑色的兄弟

* 2.1 红色的父亲,两个黑色的侄子

* 2.2 黑色的父亲,两个黑色的侄子

* 2.3 如果对面是红色侄子(位置是左边,红侄子在右边)

* 2.4 如果红色侄子和参考节点是同向(都是左边或者都是右边)

*

* */

void rb_erase(rb_tree* tree, int value)

{

    rb_node* node = tree->root;

    while (node)

    {

      if(node->data == value)

      {

          rb_erase_node(tree, node);

          return;

      }

      // find left or right

      if(value < node->data)

          node = node->left;

      else

          node = node->right;

    }

    return NULL;

}

rb_node* rb_remove_node(rb_tree* tree, rb_node* del)

{

    if(tree->root==del)

    {

        free(tree->root);

        tree->root = NULL;

        return NULL;

    }

    rb_node* parent = del->parent;

    parent->data = del->data;

    parent->left = parent->right = NULL;

    free(del);

    return parent;

}

void rb_erase_adjust(rb_tree* tree, rb_node* node)

{

    rb_node* parent = node->parent;

    if(parent == NULL)

    {

        node->color = RB_BLACK;

        return;

    }

    // 把兄弟和两个侄子节点找出来,注意,此时兄弟一定不会为空,侄子可能为空

    rb_node* brother = parent->left ^ parent->right ^ node;

    rb_node* bl = brother->left;

    rb_node* br = brother->right;

    // 红色的兄弟,此时做旋转,注意旋转之后,根节点可能指错了

    if(brother->color == RB_RED)

    {

        // 根据兄弟节点的方向,来确认旋转方向

        if(parent->left == brother)

        {

            rb_rotate_right(parent);

        }

        else

        {

            rb_rotate_left(parent);

        }

        // 重新寻找根节点,这里代码有点问题,效率低了,应该有更好的方法

        while(parent->parent)

        {

            parent = parent->parent;

        }

        tree->root = parent;

        return;

    }

    // 如果兄弟是黑的,父亲是红的,两个侄子也是黑的

    // 这种情况最简单,直接将父亲节点改成黑的,兄弟改成红的

    if(parent->color == RB_RED

            && (bl == NULL || bl->color == RB_BLACK) && (br == NULL || br->color == RB_BLACK))

    {

        brother->color = RB_RED;

        parent->color = RB_BLACK;

        return;

    }

    // 如果兄弟是黑的,父亲也是黑的,两个侄子也是黑的

    // 这种情况node本身什么颜色并不清楚,但是知道父亲在node这边少了个黑节点

    // 这种情况下做法是删除该子树一个黑节点,然后递归的整理

    if(parent->color == RB_BLACK

            && (bl == NULL || bl->color == RB_BLACK) && (br == NULL || br->color == RB_BLACK))

    {

        brother->color = RB_RED;

        rb_erase_adjust(tree, parent);

        return;

    }

    // 有一个是红色的侄子,那么兄弟显然是黑色的,父亲不知道啥颜色,node也不知道啥颜色

    // 这个情况下,分四种情况

    if((bl && bl->color == RB_RED) || (br && br->color == RB_RED))

    {


    }

}

void rb_erase_node(rb_tree* tree, rb_node* node)

{

    // 寻找删除位置,先替换删除位置,为该子树的右子树的最左边节点,或者左子树的最右边节点

    //

    // 假设我们使用左子树的最右边节点

    rb_node* del = node->left;

    if(del)

    {

        while(del->right)

        {

            del = del->right;

        }

        // 本来要删除node,但是其实把node的值,替换成del的data,再删除del

        // 其实效果是一样的,保证删除的是叶子节点,对于简化很有作用

        node->data = del->data;

    }

    else

    {

        del = node;

    }

    // 有一个儿子,这个儿子肯定是红色的,所以再替换一次

    if(del->left || del->right)

    {

        del = del->left + del->right;

        del->parent->data = del->data;

        rb_remove_node(tree, del);

        return;

    }

    // 没有儿子,并且被删除的节点是红色的,直接删除就可以了

    if(del->color == RB_RED)

    {

        rb_remove_node(tree, del);

        return;

    }

    // 没有儿子,并且被删除的节点是黑色的

    node = rb_remove_node(tree, del);

    if(node == NULL)

        return;

    rb_remove_adjust(tree, node);

}

int main()

{

    int i;

#if 1

    srand(time(NULL));

    int data[10];

    for(i=0; i

    {

        data[i] = rand()%100;

        printf("%d, ", data[i]);

    }

    printf("\n");

#else

    int data[] = {87, 88, 48, 36, 81, 83, 82, 53, 16, 99};

#endif

    rb_tree tree;

    tree.root = NULL;

    char filename[256];

    for(i=0; i

    {

        rb_node* node = malloc(sizeof(*node));

        node->data = data[i];

        rb_insert(&tree, node);

        sprintf(filename, "%d.dot", i);

        rb_draw(tree.root, filename);

    }

    return 0;

}

你可能感兴趣的:(红黑树)