红黑树学习笔记

红黑树别人已经写的很好了,我这里只是记下自己学习时的笔记。参考链接在这里https://www.cnblogs.com/skywang12345/p/3245399.html

红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
(4)如果一个节点是红色的,则它的子节点必须是黑色的。(即不能连续两个红)
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。(即黑高相等)

注意
(1) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。
(2) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。

插入时,将插入节点设为红色,直接插入,然后调整。

调整时,如果插入的是根节点则把根设为黑色;如果父节点是黑色,则不处理;只有父子为红-红时才调整,这时根据叔节点颜色和当前节点的形状分为三种情况:(1) 叔=红(2)叔=黑,并且当前为LL型(3)叔=黑,并且当前为LR型。

(1)叔=红。将父与叔设为黑,并将当前节点设为祖父节点继续调整。

(2)叔=黑,并且当前为LL型。将父设为黑,祖父设为红,对祖父节点右旋。

(3)叔=黑,并且当前为LR型。以父节点左旋,转化为LL型,再进行(2)的处理。

总结:插入时真正需要旋转调整只有 (2)叔=黑,LL型的这种情况。因为两个红色节点挨着的,肯定要变一个为黑,这时这条路的黑高就比另一条路多一,那么就通过旋转把这增加的黑色点变为两条路上公用的点。

Tips:左旋就是把该节点变为左节点,右旋就是把该节点变为右节点。

删除时,先根据二叉平衡树找到待删除节点。这时有三种情况,(1)待删除节点没有儿子,那么就删除改节点,replace_node=NULL; (2)待删除节点只有一个儿子那么删除该节点,replace_node=唯一儿子节点;(3)待删除节点有两个儿子,则去找真后继节点,并把后继节点的值赋给当前节点,转而变成删除后继节点,这将转化为(1)(2)的情况。

删除时,如果当前节点是黑色的那么肯定就要调整。

设替代节点为x,(1)如x为红,则直接将x变黑即可;(2)若x为黑且x是根节点,直接结束;(3)若x为黑且不为根这时分为4中情况:

① 兄弟为红 ②兄弟为黑且兄弟的两个孩子为黑 ③兄弟为黑且兄弟的左孩子红,右孩子黑 ④兄弟为黑且右孩子红,左任意。

列举出了所有组合的情况,不重不漏

对于①这种情况不是直接处理,而是转化为兄弟为黑的②③④的情况,因为兄弟为红那么儿子必为黑,只要变了兄弟为黑的情况就转化为②③④了。

具体过程是:将兄弟设为黑,父节点设为红,对父节点左旋。那么兄弟就变黑了。

对于②这种情况直接把兄弟变红,然后当前节点设为父节点递归调整。

对于③这种情况不是直接处理,而是转化为④的情况。

具体过程是:把兄弟的左儿子设黑,兄弟设红,对兄弟节点右旋。此时兄弟变了。

对于④这种情况把父节点颜色赋值给兄弟,把父节点设黑,把兄弟的右儿子设黑,对当前节点的父节点左旋,然后当前节点设为根节点进行最终调整。(因为这时黑高已经平衡了,只需检查下根节点)

总结:删除时的调整主要是因为一侧的黑高是h-1,一侧是h,主要就是通过各种旋转使得黑高相等。同时,会不断让当前节点往根节点移动,就是去走到递归边界。

删除是真的复杂!,这些所有情况都需要有具体的图才直观,可参考这里

下面是自己写的插入操作,当作纪念。

#include<bits/stdc++.h>
using namespace std;

class RBNode{
public:
    int val;
    int c;  // 0 -> red   1-> black
    RBNode *left;
    RBNode *right;
    RBNode *parent;
    RBNode(int v,int color){
        val=v,c=color;
        left=right=parent=NULL;
    }
};
void setB(RBNode*p){
    p->c=1;
}
void setR(RBNode*p){
    p->c=0;
}
void leftRotate(RBNode* &rt, RBNode *p){
    RBNode *y=p->right;
    p->right=y->left;
    if(p->right) {
        p->right->parent=p;
    }
    y->parent=p->parent;
    if(y->parent){
        if(y->parent->left==p) y->parent->left=y;
        else y->parent->right=y;
    }else {
        rt=y;
    }
    y->left=p;
    p->parent=y;
}
void rightRotate(RBNode *&rt,RBNode*p){
    RBNode *y=p->left;
    p->left=y->right;
    if(p->left){
        p->left->parent=p;
    }
    y->parent=p->parent;
    if(y->parent){
        if(y->parent->left==p) y->parent->left=y;
        else y->parent->right=y;
    }else {
        rt=y;
    }
    p->parent=y;
    y->right=p;
}
void insertFix(RBNode* rt,RBNode *p){
    RBNode *par,*gpar;
    while((par=p->parent)&&par->c==0){
        gpar = par->parent;
        if(par==gpar->left){
            RBNode *uncle=gpar->right;
            if(uncle && uncle->c==0){
                setB(par);
                setB(uncle);
                setR(gpar);
                p=gpar;
                continue;
            }
            if(par->right==p){
                leftRotate(rt,par);
                swap(par,p);
            }
            setB(par);
            setR(gpar);
            rightRotate(rt,gpar);
        }else{
            RBNode *uncle=gpar->left;
            if(uncle&&uncle->c==0) {
                setB(par);
                setB(uncle);
                setR(gpar);
                p=gpar;
                continue;
            }
            if(par->left==p){
                rightRotate(rt,par);
                swap(par,p);
            }
            setB(par);
            setR(gpar);
            leftRotate(rt,gpar);
        }
    }
    setB(rt);
}
void insert(RBNode* &rt, int v){
    RBNode *p=new RBNode(v,0);
    RBNode* x=rt;
    RBNode* y=NULL;
    while(x!=NULL){
        y=x;
        if(v<x->val) x=x->left;
        else x=x->right;
    }
    p->parent=y;
    if(y!=NULL){
        if(p->val<y->val) y->left=p;
        else y->right=p;
    }else rt=p;
    insertFix(rt, p);
}

int main(){
    RBNode *rt=NULL;
    insert(rt, 3);
    insert(rt, 4);
    insert(rt, 2);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值