zoukankan      html  css  js  c++  java
  • 【数据结构】红黑树 C语言代码

    连看带写花了三天,中途被指针引用搞得晕晕乎乎的。 插入和删除的调整过程没有看原理,只看了方法,直接照着写的。

    看了两份资料,一份是算法导论第12-13章, 另一份是网上的资料http://blog.csdn.net/v_JULY_v/article/details/6105630

    下面C代码是我根据 算法导论的伪码写的。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef int DataType;
    
    typedef struct RBNode
    {
        RBNode *parent, *left, *right; //指向结点的父结点、左右孩子结点
        DataType key;  //结点数据
        int color; //颜色 红(r) 或 黑(b)
    }RBNode; //定义红黑树结点
     
    
    RBNode Nil;
    RBNode * nil = &Nil;
    
    
    void left_rotate( RBNode * &T, RBNode * x) //左旋  x一定不能有引用 因为如果引用后 x与y->parent就是等价的了, y->parent改变 x就会改变
    {
        RBNode * y; 
        y = x->right;
        /************第一部分 y的左孩子 与 x间关联*************/
        x->right = y->left;      //x认右孩子
        if(y->left != nil)
        {
            y->left->parent = x;  //孩子认parent
        }
        /************第一部分 y的左孩子 与 x间关联 end*************/
    
        /************第二部分 y 与 x的parent 关联*************/
        y->parent = x->parent;   //y认 x的parent为自己的parent   //y的parent与x的地址是一样的
    
        int isroot = 0;
        if(x->parent == nil)    //x的parent根据自己的情况 认y为左或右孩子
        {
            isroot = 1;
        }
        else if(x == x->parent->left)
        {
            x->parent->left = y;
        }
        else
        {
            x->parent->right = y;
        }
        /************第二部分 y 与 x的parent 关联 end*************/
    
        /************第部分 x 与 y的关联 *************/
        y->left = x;  //y认x为孩子
        x->parent = y; //x认y为parent
        /************第部分 x 与 y的关联 end*************/
        if(isroot == 1)
        {
            T = y;
        }
    }
    
    void right_rotate(RBNode * &T, RBNode * x) //右旋
    {
        RBNode * y; 
        y = x->left;
    
        x->left = y->right;
    
        if(y->right != nil)
        {
            y->right->parent = x;
        }
    
        y->parent = x->parent;
        int isroot = 0;
        if(x->parent == nil)
        {
            isroot = 1;
        }
        else if(x == x->parent->right)
        {
            x->parent->right = y;
        }
        else
        {
            x->parent->left = y;
        }
    
        y->right = x;
        x->parent = y;
    
        if(isroot == 1)
        {
            T = y;
        }
    }
    
    void rb_insert_fixup(RBNode * &T, RBNode * z) //红黑树插入后的调整  注意z不能要引用 因为调整的过程中z的值作为位置标记会改变 但我们不希望树的结构因为z而变化
    {
    
        RBNode * y;
            while(z->parent->color == 'r')
            {
                if(z->parent == z->parent->parent->left)    //z的parent是左子的情况
                {
                    //copy(z->parent->parent->right, y);
                    y = z->parent->parent->right;
                    if(y->color == 'r')        //情况1 z的parent和uncle都是红色 把这两个红色染成黑色 把grandparent染成红色 令z = grandparent 再次循环
                    {
                        y->color = 'b';
                        z->parent->color = 'b';
                        z->parent->parent->color = 'r';
                        z = z->parent->parent;
                    }
                    else if(z == z->parent->right)  //当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子 对策:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋。
                    {
                        z = z->parent;
                        left_rotate(T, z);
                    }
                    else //当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子 解法:父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋
                    {
                        z->parent->color = 'b';
                        z->parent->parent->color = 'r';
                        right_rotate(T, z->parent->parent);
                    }
                }
                else //z的parent是右子的情况
                {
                    y = z->parent->parent->left;
                    if(y->color == 'r')
                    {
                        z->parent->color = 'b';
                        y->color = 'b';
                        z->parent->parent->color = 'r';
                        z = z->parent->parent;
                    }
                    else if(z == z->parent->left)
                    {
                        z = z->parent;
                        right_rotate(T, z);
                    }
                    else
                    {
                        z->parent->color = 'b';
                        z->parent->parent->color = 'r';
                        left_rotate(T, z->parent->parent);
                    }
                }
            }
    
        if(z->parent == nil)
        {
            z->color = 'b';
            return;
        }
        else
        {
            return;
        }
    }
    
    void rb_insert(RBNode * &T, RBNode * z)  //红黑树 插入工作 注意 z不要有引用 
    {
        RBNode * y = nil;
        RBNode * x = T;
        while(x != nil)  //找到z适当的插入位置
        {
            y = x;
            if(z->key < x->key)
                x = x->left;
            else
                x = x->right;
        }
    
        z->parent = y;
        if(y == nil)  //parent 认孩子总是麻烦一些的 毕竟要区分是左是右 是否为根
        {
            T = z;
        }
        else if(z->key < y->key)
        {
            y->left = z;
        }
        else
        {
            y->right = z;
        }
    
        //对新插入的点处理, 染成红色
        z->left = nil;
        z->right = nil;
        z->color = 'r';
        
        //调整红黑树
        rb_insert_fixup(T, z);
    
    }
    
    RBNode * rb_findmax(RBNode * z)  //找到以z为树根的树的最大结点
    {
        while(z->right != nil)
        {
            z = z->right;
        }
        return z;
    }
    
    RBNode * rb_findmin(RBNode * z)  //找到以z为树根的树的最小结点
    {
        while(z->left != nil)
        {
            z = z->left;
        }
        return z;
    }
    
    RBNode * rb_successor(RBNode * z) //找z的后继
    {
        if(z->right != nil)
        {
            return rb_findmin(z->right);  //如果z的right不为空 后继就是z的右子树中最小的点
        }
        else
        {
            RBNode * y = z->parent;
            while(y != nil && z == y->right)
            {
                z = y;
                y = y->parent;
            }
            return y;
        }
    }
    
    void rb_delete_fixup(RBNode * &T, RBNode * x)
    {
        RBNode* w;
        while(x != T && x->color == 'b')
        {
            if(x == x->parent->left)
            {
                w = x->parent->right;
                if(w->color == 'r')
                {
                    w->color = 'b';
                    x->parent->color = 'r';
                    left_rotate(T, x->parent);
                    
                    w = x->parent->right;
                }
                if(w->left->color == 'b' && w->right->color == 'b')
                {
                    w->color = 'r';
                    x = x->parent;
                }
                else
                {
                    if(w->right->color == 'b')
                    {
                        w->left->color = 'b';
                        w->color = 'r';
                        right_rotate(T, w);
                        w = x->parent->right;
                    }    
    
                    w->color = x->parent->color;
                    x->parent->color = 'b';
                    w->right->color = 'b';
                    left_rotate(T, x->parent);
                    x = T;
                }        
            }
            else
            {
                w = x->parent->left;
                if(w->color == 'r')
                {
                    w->color = 'b';
                    x->parent->color = 'r';
                    right_rotate(T, x->parent);
                    
                    w = x->parent->left;
                }
                if(w->left->color == 'b' && w->right->color == 'b')
                {
                    w->color = 'r';
                    x = x->parent;
                }
                else if(w->left->color == 'b')
                {
                    if(w->left->color == 'b')
                    {
                        w->right->color = 'b';
                        w->color = 'r';
                        left_rotate(T, w);
                        w = x->parent->left;
                    }
                
                    w->color = x->parent->color;
                    x->parent->color = 'b';
                    w->left->color = 'b';
                    right_rotate(T, x->parent);
                    x = T;
                }        
            }
        }
        x->color = 'b';
    }
    
    RBNode * rb_delete(RBNode * &T, RBNode * z) //红黑树 删除节点
    {
        //y 确定删除的结点是z还是z的后继
        RBNode * y;
        y = (z->left == nil || z->right == nil) ? z : rb_successor(z);
    
        //x 是y的非nil子女 或是 nil
        RBNode * x;
        x = (y->left != nil) ? y->left : y->right;
    
        //无条件令x的parent = y的parent 
        x->parent = y->parent;
    
        //删除y 建立x与y的parent之间的联系
        if(y->parent == nil)
        {
            T = x;
        }
        else if(y == y->parent->left)
        {
            y->parent->left = x;
        }
        else
        {
            y->parent->right = x;
        }
    
        //如果y!=z 将y的数据拷贝到z
        if(y != z)
        {
            //z的颜色不变
            z->parent = y->parent;
            z->left = y->left;
            z->right = y->right;
            z->key = y->key;
        }
    
        if(y->color == 'b')
        {
            rb_delete_fixup(T, x);
        }
        return y;
    }
    int main()
    {
        nil->color = 'b';  //叶子结点都是黑的
        nil->left = nil;
        nil->right = nil;
        nil->parent = nil;
        RBNode *T;
        T = nil;
        RBNode data[10];
        for(int i = 0; i < 10; i++)
        {
            data[i].key = i + 1;
            RBNode * z = &data[i];
            rb_insert(T, z);
        }
    
        RBNode * x = T->left->left;
        rb_delete(T, x);
    
        return 0;
    }
  • 相关阅读:
    $route 侦听路由参数的变化
    vue移动端(持续更新......)
    vue本地开发配置及项目部署
    vue解决虚拟dom复用的问题
    移动端头部固定中间内容滚动
    VUE的路由懒加载及组件懒加载
    VUEX(状态管理)之憨憨篇
    Go-第一篇
    高精度1
    牛客练习赛61
  • 原文地址:https://www.cnblogs.com/dplearning/p/3883700.html
Copyright © 2011-2022 走看看