c语言红黑二叉树

今天讨论组看了一个笑话,但是主要内容则是一个女程序员五分钟用c写了一个红黑树,第一次听说,不懂,然后查了一下,下面程序不是博主写的,博主简单了解了一下,然后自己也有点观点:

听学长说有去腾讯面试android的,还是工作了几年的,自我感觉不错的,然后面试官出的问题让他很费解,基本都是出的c语言的,当时博主也不知道为啥,现在才略明白点,简单来说,就拿android中的actionbar来说吧,貌似就是底层封装的c,而且还是仿的苹果的,苹果用的oc,但是继承的c,相信大家基本明白了吧,学习编码不是程序本身,而且思想,老规矩,废话不多说,上代码

/* 
性质1. 节点是红色或黑色 
性质2. 根是黑色 
性质3. 每个红色节点的两个子节点都是黑色 (从每个叶子到根的所有路径上不能有两个连续的红色节点) 
性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点 
*/ 
  
#include <stdio.h> 
#include <stdlib.h> 
typedef enum Color //定义红黑树结点颜色颜色类型 
{ 
    RED = 0, 
    BLACK = 1 
}Color; 
  
typedef struct Node //定义红黑树结点类型 
{ 
    struct Node *parent; 
    struct Node *left; 
    struct Node *right; 
    int value; 
    Color color; 
}Node, *Tree; 
Node *nil=NULL; //为了避免讨论结点的边界情况,定义一个nil结点代替所有的NULL 
  
Node* Parent(Node *z) //返回某结点的父母 
{ 
    return z->parent; 
} 
Node* Left(Node *z) //返回左子树 
{ 
    return z->left; 
} 
Node *Right(Node *z) //返回右子树 
{ 
    return z->right; 
} 
void LeftRotate(Tree &T, Node *x) //左旋转:结点x原来的右子树y旋转成为x的父母 
{ 
    if( x-> right != nil ) 
    { 
        Node *y=Right(x); 
        x->right=y->left; 
        if(y->left != nil) 
        { 
            y->left->parent=x; 
        } 
        y->parent=x->parent; 
        if( x->parent == nil ) 
        { 
            T=y; 
        } 
        else 
        { 
            if( x == Left(Parent(x)) ) 
            { 
                x->parent->left=y; 
            } 
            else 
            { 
                x->parent->right=y; 
            } 
        } 
        y->left=x; 
        x->parent=y; 
    } 
    else 
    { 
        printf("%s/n","can't execute left rotate due to null right child"); 
    } 
} 
  
void RightRotate(Tree &T, Node *x) //右旋转:结点x原来的左子树y旋转成为x的父母 
{ 
    if( x->left != nil ) 
    { 
        Node *y=Left(x); 
        x->left=y->right; 
        if( y->right != nil ) 
        { 
            y->right->parent=x; 
        } 
        y->parent=x->parent; 
        if( x->parent == nil ) 
        { 
            T=y; 
        } 
        else 
        { 
            if(x == Left(Parent(x)) ) 
            { 
                x->parent->left=y; 
            } 
            else 
            { 
                x->parent->right=y; 
            } 
        } 
        y->right=x; 
        x->parent=y; 
    } 
    else 
    { 
        printf("%s/n","can't execute right rotate due to null left child"); 
    } 
  
} 
  
void InsertFixup(Tree &T, Node *z) //插入结点后, 要维持红黑树四条性质的不变性 
{ 
    Node *y; 
    while( Parent(z)->color == RED ) //因为插入的结点是红色的,所以只可能违背性质3,即假如父结点也是红色的,要做调整 
    { 
        if( Parent(Parent(z))->left == Parent(z) ) //如果要插入的结点z是其父结点的左子树 
        { 
            y=Parent(Parent(z))->right; // y设置为z的叔父结点 
            if( y->color == RED ) //case 1: 如果y的颜色为红色,那么将y与z的父亲同时着为黑色,然后把z的 
            { //祖父变为红色,这样子z的祖父结点可能违背性质3,将z上移成z的祖父结点 
                y->color=BLACK; 
                z->parent->color=BLACK; 
                z->parent->parent->color=RED; 
                z=z->parent->parent; 
            } 
            else 
            { 
                if( z == z->parent->right ) //case 2: 如果y的颜色为黑色,并且z是z的父母的右结点,则z左旋转,并且将z变为原来z的parent. 
                { 
                    z=z->parent; 
                    LeftRotate(T, z); 
                } 
                z->parent->color=BLACK; //case 3: 如果y的颜色为黑色,并且z是z的父母的左结点,那么将z的 
                z->parent->parent->color=RED; //父亲的颜色变为黑,将z的祖父的颜色变为红,然后旋转z的祖父 
                RightRotate(T,z->parent->parent); 
            } 
        } 
        else //与前一种情况对称,要插入的结点z是其父结点的右子树,注释略去 
        { 
            y=Parent(Parent(z))->left; 
            if( y->color == RED) 
            { 
                z->parent->color=BLACK; 
                y->color=BLACK; 
                z->parent->parent->color=RED; 
                z=z->parent->parent; 
            } 
            else 
            { 
                if( z == z->parent->left ) 
                { 
                    z=z->parent; 
                    RightRotate(T,z); 
                } 
                z->parent->color=BLACK; 
                z->parent->parent->color=RED; 
                LeftRotate(T,z->parent->parent); 
            } 
        } 
    } 
    T->color=BLACK; //最后如果上升为T的根的话,把T的颜色设置为黑色 
} 
void Insert(Tree &T, int val) //插入结点 
{ 
    if(T == NULL) //初始化工作:如果根尚不存在,那么new一个新结点给根,同时new一个新结点给nil 
    { 
        T=(Tree)malloc(sizeof(Node)); 
        nil=(Node*)malloc(sizeof(Node)); 
        nil->color=BLACK; //nil的颜色设置为黑 
        T->left=nil; 
        T->right=nil; 
        T->parent=nil; 
        T->value=val; 
        T->color=BLACK; //为了满足性质2,根的颜色设置为黑色 
    } 
    else //如果此树已经不为空,那么从根开始,从上往下查找插入点 
    { 
        Node *x=T; //用x保存当前顶点的父母结点,用p保存当前的结点 
        Node *p=nil; 
        while(x != nil) //如果val小于当前结点的value值,则从左边下去,否则从右边下去 
        { 
            p=x; 
            if(val < x->value ) 
            { 
                x=x->left; 
            } 
            else if(val > x->value) 
            { 
                x=x->right; 
            } 
            else 
            { 
                printf("%s %d/n","duplicate value",val); //如果查找到与val值相同的结点,则什么也不做,直接返回 
                return; 
            } 
  
        } 
        x=(Node*)malloc(sizeof(Node)); 
        x->color=RED; //新插入的结点颜色设置为红色 
        x->left=nil; 
        x->right=nil; 
        x->parent=p; 
        x->value=val; 
        if( val < p->value ) 
        { 
            p->left = x; 
        } 
        else 
        { 
            p->right = x; 
        } 
          
        InsertFixup(T, x); //插入后对树进行调整 
          
    } 
} 
  
Node* Successor(Tree &T, Node *x) //寻找结点x的中序后继 
{ 
    if( x->right != nil ) //如果x的右子树不为空,那么为右子树中最左边的结点 
    { 
        Node *q=nil; 
        Node *p=x->right; 
        while( p->left != nil ) 
        { 
            q=p; 
            p=p->left; 
        } 
        return q; 
    } 
    else //如果x的右子树为空,那么x的后继为x的所有祖先中为左子树的祖先 
    { 
        Node *y=x->parent; 
        while( y != nil && x == y->right ) 
        { 
            x=y; 
            y=y->parent; 
        } 
          
        return y; 
    } 
} 
  
void DeleteFixup(Tree &T, Node *x) //删除黑色结点后,导致黑色缺失,违背性质4,故对树进行调整 
{ 
    while( x != T && x->color == BLACK ) //如果x是红色,则直接把x变为黑色跳出循环,这样子刚好补了一重黑色,也满足了性质4 
    { 
        if( x == x->parent->left ) //如果x是其父结点的左子树 
        { 
            Node *w=x->parent->right; //设w是x的兄弟结点 
            if( w->color == RED ) //case 1: 如果w的颜色为红色的话 
            { 
                w->color=BLACK; 
                x->parent->color=RED; 
                LeftRotate(T, x->parent); 
                w=x->parent->right; 
            } 
            if( w->left->color == BLACK && w->right->color == BLACK ) //case 2: w的颜色为黑色,其左右子树的颜色都为黑色 
            { 
                w->color=RED; 
                x=x->parent; 
            } 
            else if( w->right->color == BLACK ) //case 3: w的左子树是红色,右子树是黑色的话 
            { 
                w->color=RED; 
                w->left->color=BLACK; 
                RightRotate(T, w); 
                w=x->parent->right; 
            } 
            w->color=x->parent->color; //case 4: w的右子树是红色 
            x->parent->color=BLACK; 
            w->right->color=BLACK; 
            LeftRotate(T , x->parent); 
              
            x=T; 
        } 
        else //对称情况,如果x是其父结点的右子树 
        { 
            Node *w=x->parent->left; 
            if( w->color == RED ) 
            { 
                w->color=BLACK; 
                x->parent->color=RED; 
                RightRotate(T, x->parent); 
                w=x->parent->left; 
            } 
            if( w->left->color == BLACK && w->right->color == BLACK ) 
            { 
                w->color=RED; 
                x=x->parent; 
            } 
            else if( w->left->color == BLACK ) 
            { 
                w->color=RED; 
                w->right->color=BLACK; 
                LeftRotate(T, w); 
                w=x->parent->left; 
            } 
            w->color=x->parent->color; 
            x->parent->color=BLACK; 
            w->left->color=BLACK; 
            RightRotate(T , x->parent); 
              
            x=T; 
              
        } 
    } 
    x->color=BLACK; 
} 
  
void Delete(Tree &T, Node *z) //在红黑树T中删除结点z 
{ 
    Node *y; //y指向将要被删除的结点 
    Node *x; //x指向将要被删除的结点的唯一儿子 
    if( z->left == nil || z->right == nil ) //如果z有一个子树为空的话,那么将直接删除z,即y指向z 
    { 
        y=z; 
    } 
    else 
    { 
        y=Successor(T, z); //如果z的左右子树皆不为空的话,则寻找z的中序后继y, 
    } //用其值代替z的值,然后将y删除 ( 注意: y肯定是没有左子树的 ) 
    if( y->left != nil ) //如果y的左子树不为空,则x指向y的左子树 
    { 
        x=y->left; 
    } 
    else 
    { 
        x=y->right; 
    } 
    x->parent=y->parent; //将原来y的父母设为x的父母,y即将被删除 
    if( y->parent == nil ) 
    { 
        T=x; 
    } 
    else 
    { 
        if( y == y->parent->left ) 
        { 
            y->parent->left=x; 
        } 
        else 
        { 
            y->parent->right=x; 
        } 
    } 
    if( y != z ) //如果被删除的结点y不是原来将要删除的结点z, 
    { //即只是用y的值来代替z的值,然后变相删除y以达到删除z的效果 
        z->value=y->value; 
    } 
    if( y->color == BLACK ) //如果被删除的结点y的颜色为黑色,那么可能会导致树违背性质4,导致某条路径上少了一个黑色 
    { 
        DeleteFixup(T, x); 
    } 
} 
Node* Search(Tree T, int val) 
{ 
    if( T != nil ) 
    { 
        if( val < T->value ) 
        { 
            Search(T->left, val); 
        } 
        else if ( val > T->value ) 
        { 
            Search(T->right,val); 
        } 
        else 
        { 
            return T; 
        } 
    } 
} 
  
void MidTranverse(Tree T) 
{ 
    if( T != NULL && T != nil ) 
    { 
        MidTranverse(T->left); 
        printf("%d ",T->value); 
        MidTranverse(T->right); 
    } 
  
} 
int main() 
{ 
    Tree t=NULL; 
    Insert(t,30); 
    Insert(t,50); 
    Insert(t,65); 
    Insert(t,80); 
    Delete(t,Search(t,30)); 
    Delete(t,Search(t,65)); 
    MidTranverse(t); 
    return 0; 
}


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值