红黑树

红黑树说难不难,说简单不简单,我去看别人写的红黑树教学,是真的看不懂,于是自己想办法,实现了。

红黑树性质:

性质1. 节点是红色或黑色。

性质2. 根节点是黑色。

性质3 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

插入:

插入的节点是红色节点,当插入节点的父亲节点是红色时,把父亲的颜色改为黑色。

删除:

先找到删除的目标节点,如果它没有儿子,或只有一个儿子,就地删除它,

否则递归寻找它的前驱,用前驱替代目标节点,删除前驱。

修正:

将插入,删除节点,引发的违背红黑树性质的行为,全部归为黑高不相等来进行黑高修正。

大致可分为五种情况,以较高子树作为基础先判断:

(以下以B代表黑色节点,R代表红色节点,同侧是指都是在一个节点的右边(或左边)的父亲和儿子节点)

1.它是B

1.1父同侧的儿子是B

1.1.1另一侧儿子是B

1.1.2另一侧儿子是R

1.2父同侧儿子是R

 

2.它是R

2.1兄弟是B

 

2.2兄弟是R

 

  1.          1.1.1 情况,B -> (B, B),改为R->(B,B)即可,如果父亲也是R,则改父亲为B。
  2.          1.1.2 情况,B -> (R, B) ,向父亲方向旋转,然后酌情考虑一些变色操作即可平衡。
  3.          1.2 情况,B -> (?, R) ,想方设法将R节点上升作为子树的根节点(两次旋转),然后酌情考虑一些变色操作即可平                    衡。
  4.          2.1 情况,R -  B,向父亲方向旋转,然后交换父亲R,和另一个兄弟B的颜色,然后递归再去处理兄弟B的平衡(转化                  为前3种情况)。
  5.          2.2 情况,R - R,把兄弟R改为B,即可平衡。

 

不画图出来推敲是不可能理解的,

高子树是左孩子右孩子都一样,

以上五种情况,只有第一种情况可能需要不断向上递归处理,其余情况均可在几次旋转之内操作达到平衡。

 

#include <iostream>
#include <cstdio>
#define max(a, b) (a > b? a: b)
using namespace std;
enum Color {red, black};
class Tree {
public:
    Color color;
    int num, num2, value, bHeight;
    //num当前节点元素个数, num2当前子树元素个数
    Tree *lChild, *rChild;
};
Tree *T, *NIL;
//NIL哨兵节点
inline void updateNode(Tree *th) {
    if (th != NIL) {
        th->num2 = th->lChild->num2 + th->rChild->num2 + th->num;
        th->bHeight = max(th->lChild->bHeight, th->rChild->bHeight) + (th->color == black);
    }
}
//旋转,op = true右旋, op = false左旋
inline void rTurn(Tree *&th, bool op = true) {
    Tree *q = th;
    if (op) {
        th = th->lChild;
        q->lChild = th->rChild;
        th->rChild = q;
    } else {
        th = th->rChild;
        q->rChild = th->lChild;
        th->lChild = q;
    }
}
void balance(Tree *par, Tree *&th) {
    if (th != NIL) {
        if (th->lChild->bHeight != th->rChild->bHeight) {
            bool op = th->lChild->bHeight > th->rChild->bHeight;
            Tree *&th1 = op? th->lChild: th->rChild;
            Tree *&th3 = op? th1->rChild: th1->lChild;
            if (th1->color == black) {
                if (th3->color == black) {
                    Tree *th4 = op? th1->lChild: th1->rChild;
                    if (th4->color == black) {
                        //1.B->(B, B)
                        th1->color = red;
                        if (th->color == red) {
                            th->color = black;
                        }
                    } else {
                        //2.B->(R, B)
                        rTurn(th, op);
                        if ((op? th->rChild: th->lChild)->color == black) {
                            th4->color = black;
                        }
                    }
                } else {
                    //3.B->(?, R)
                    rTurn(th1, !op);
                    rTurn(th, op);
                    Tree *q = op? th->rChild: th->lChild;
                    if (q->color == red) {
                        q->color = black;
                        if (par == NIL) {
                            th->color = black;
                        }
                    } else {
                        th->color = black;
                    }
                }
            } else {
                Tree *&th2 = op? th->rChild: th->lChild;
                if (th2->color == black) {
                    //4.R-B
                    rTurn(th, op);
                    th->color = black;
                    (op? th->rChild: th->lChild)->color = red;
                    balance(th, op? th->rChild: th->lChild);
                } else {
                    //5.R-R
                    th2->color = black;
                }
            }

        }
        if (th->lChild != NIL) updateNode(th->lChild);
        if (th->rChild != NIL) updateNode(th->rChild);
        updateNode(th);
    }
}
void insertNode(Tree *&th, int value, Tree *par = NIL) {
    if (th == NIL) {
        Tree *q = new Tree;
        q->num = q->num2 = 1;
        q->value = value;
        q->lChild = q->rChild = NIL;
        q->bHeight = 1;
        q->color = par == NIL? black: red;
        if (par->color == red) {
            par->color = black;
            ++par->bHeight;
        }
        th = q;
    } else if (th->value == value) {
        ++th->num;
        ++th->num2;
    } else {
        insertNode(value < th->value? th->lChild: th->rChild, value, th);
    }
    balance(par, th);
}
void deleteNode(Tree *&th, int value, Tree *&par = NIL, Tree *q = NULL) {
    if (q == NULL) {
        if (th == NIL) {
            return ;
        } else if (th->value == value){
            if (th->num > 1) {
                --th->num;
                --th->num2;
            } else if (th->lChild == NIL || th->rChild == NIL){
                Tree *p = th;
                th = th->lChild == NIL? th->rChild: th->lChild;
                delete  p;
            } else {
                deleteNode(th->lChild, value, th, th);
            }
        } else {
            deleteNode(value < th->value? th->lChild: th->rChild, value, th);
        }
    } else {
        if (th == NIL) {
            q->num = par->num;
            q->value = par->value;
            Tree *p = par;
            par = par->lChild;
            delete p;
        } else {
            deleteNode(th->rChild, value, th, q);
        }
    }
    balance(par, th);
}
int getRank(Tree *th, int value) {
    if (th == NIL){
        return 0;
    } else if (th->value < value){
        return th->lChild->num2 + th->num + getRank(th->rChild, value);
    } else {
        return getRank(th->lChild, value);
    }
}
int getSa(Tree *th, int sa) {
    if (th == NIL){
        return -1;
    } else{
        int lower_sa = th->lChild->num2 + 1;
        int upper_sa = lower_sa + th->num;
        if (sa >= lower_sa && sa < upper_sa) {
            return th->value;
        } else if (sa < lower_sa) {
            return getSa(th->lChild, sa);
        } else {
            return getSa(th->rChild, sa - upper_sa + 1);
        }
    }
}
int getPre(Tree *th, int value) {
    if (th == NIL) {
        return -1 << 30;
    } else if (th->value < value) {
        int x = getPre(th->rChild, value);
        return (x != -1 << 30)? x: th->value;
    } else {
        return getPre(th->lChild, value);
    }
}
int getSuf(Tree *th, int value) {
    if (th == NIL) {
        return 1 << 30;
    } else if (th->value > value) {
        int x = getSuf(th->lChild, value);
        return (x != 1 << 30)? x: th->value;
    } else {
        return getSuf(th->rChild, value);
    }
}
int main()
{
    NIL = new Tree;
    NIL->num = NIL->num2 = 0;
    NIL->color = black;
    NIL->bHeight = 0;
    T = NIL;
    int n, opt, x;
    scanf("%d", &n);
    int i = 0;
    for(i = 0; i < n; i++) {
        scanf("%d%d", &opt, &x);
        switch (opt) {
        case 1:insertNode(T, x);break;
        case 2:deleteNode(T, x);break;
        case 3:printf("%d\n", getRank(T, x) + 1);break;
        case 4:printf("%d\n", getSa(T, x));break;
        case 5:printf("%d\n", getPre(T, x));break;
        case 6:printf("%d\n", getSuf(T, x));break;
        }
    }
    return 0;
}

写完插入,删除,查找排名,前驱后继等,也有210行这种了,也不简单了。

题目:洛谷普通平衡树

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值