算法-16-红黑树

目录

1、定义

2、特点

3、完成代码

4、旋转---rotateLeft()

5、向一棵2-结点树中插入新键---put()

6、向树底部的2-结点插入新键---put()

7、向一个3-结点中插入新键---flipColors()

8、向树底部3-结点插入新键

9、put()---插入规则

10、红黑树的构造轨迹


1、定义

通过前面算法-15-平衡查找树的学习,我们了解到要想实现平衡的二叉树,我们需要2-3结点的二叉查找树思想。如果你能完全理解2-3二叉查找树的话,你理解红黑树将简单很多。也知道红黑树是通过什么思想来保证平衡性的。

红黑二叉查找树背后的基本思想是用标准的二叉查找树(完 全由2-结点构成)和一些额外的信息(替换3-结点)来表示2-3 树。 

我们通过红色链接,来将两个结点连接起来构造成一个3-结点,黑色链接是2-3树中的普通链接。

2、特点

红黑树要想和2-3树一一对应,那么它必须含有以下定义:

  • 根节点总是黑色的
  •  红链接均为左链接;
  •  没有任何一个结点同时和两条红链接相连;
  •  该树是完美黑色平衡的,即任意空链接到根结点的路径上的黑链接数量相同。 

3、完成代码

public class RedBlackTree<Key extends Comparable<Key>,Value> {

    private static final boolean RED=true;
    private static final boolean BLACK=false;

    private Node root;
    class Node{
        Key key;
        Value val;
        int N;//这棵子树的结点总数
        Node left,right;
        boolean color;

        public Node(Key key,Value val,int N,boolean color){
            this.key=key;
            this.val=val;
            this.N=N;
            this.color=color;
        }
    }

    public void put(Key key,Value value){

      root=put(root,key,value);
      root.color=BLACK;//根节点永远是黑色

    }
    /**
     * 1、 如果右子结点是红色的而左子结点是黑色 的,进行左旋转;
     * 2、 如果左子结点是红色的且它的左子结点也是红色的,进行右旋转;
     * 3、 如果左右子结点均为红色,进行颜色转换。 
     */
    private Node put(Node h, Key key, Value value) {

        if (h==null) return new Node(key,value,1,RED);

        int cmp=key.compareTo(h.key);
        if (cmp<0) h.left=put(h.left,key,value);
        else if (cmp>0) h.right=put(h.right,key,value);
        else h.val=value;

        if (isRed(h.right)&&!isRed(h.left)) h=rotateLeft(h);
        if (isRed(h.left)&&isRed(h.left.left))h=rotateRight(h);
        if (isRed(h.left)&&isRed(h.right)) flipColors(h);

        h.N=size(h.left)+size(h.right)+1;
        return h;

    }

    public Value get(Key key) {
        return get(root, key);
    }
    /**
     * 使用递归的方式,从根节出发,不断向下查找
     */
    private Value get(Node node, Key key) {
        if (node == null) {
            return null;
        }
        int cmp = key.compareTo(node.key);
        if (cmp < 0) {
            return get(node.left, key);
        } else if (cmp > 0) {
            return get(node.right, key);
        } else {
            return node.val;
        }
    }

    private void flipColors(Node h){
        h.color= RED;
        h.left.color=BLACK;
        h.right.color=BLACK;
    }

    private  Node rotateLeft(Node h){
        Node x=h.right;
        h.right=x.left;
        x.left=h;
        x.color=h.color;
        h.color=RED;
        x.N=h.N;
        h.N=size(h.left)+size(h.right)+1;
        return x;
    }

    private Node rotateRight(Node h){
        Node x=h.left;
        h.left=x.right;
        x.right=h;
        x.color=h.color;
        h.color=RED;
        x.N=h.N;
        h.N=size(h.left)+size(h.right)+1;
        return x;
    }

    public int size(Node node) {
        if (node == null) return 0;
        return node.N;
    }
    private boolean isRed(Node x){
        if (x==null) return false;//树最底部空结点都是黑色链接
        return x.color==RED;
    }

}

4、旋转---rotateLeft()

在我们实际操作过程红,比如删除一个结点或者插入一个结点时候,我们会出现红色右链接或者一个结点连接着两条红色链接的情况。

这个时候我们就需要进行旋转来恢复红黑树的有序性和完美平衡性。

5、向一棵2-结点树中插入新键---put()

我们新增结点会默认该节点为红链接,然后通过从底部不断的旋转到根节点来恢复树的平衡性,假设这棵红黑树只有一个根结点,如果我们插入的新键比根节点小,那么我们直接新增一个红色的左结点就可以了,如果我们新增的结点比根结点大,那么我们就新增了一个红色了右连接,这时候我们就需要旋转。

6、向树底部的2-结点插入新键---put()

我们插入一个新结点的时候,会默认这个结点为红色,如果他刚好在右连接,就得进行旋转,左连接就不需要。

7、向一个3-结点中插入新键---flipColors()

在一棵2-3树中,当只有一个3-结点时,我们插入一个新键的时候,我们需要先把它变成一个4-结点树(3个键,四条链接)然后再把它转换成一颗3个2-结点的树,这样我们就保证了树的平衡性。

变成一个4-结点,在红黑树中就是一个结点同时连接着两个红色链接,把它拆分成3个2-结点,就是将这两个红色链接都变黑。

8、向树底部3-结点插入新键

向树底部的3-结点插入新键的时候,首先我们会形成4-结点(一个结点连接着两条红色链接),然后把4-结点中3个键中间那个键移动给父结点,同时拆分这个4-结点为2个2-结点。如果父结点也是一个3-结点,那么继续重复前面的步骤直到遇到根节点或者一个2-结点的父结点。

9、put()---插入规则

在沿着 插入点到根结点的路径向上移动时在所经过的每 个结点中顺序完成以下操作,我们就能完成插入 操作:

  1. 如果右子结点是红色的而左子结点是黑色 的,进行左旋转;
  2. 如果左子结点是红色的且它的左子结点也是红色的,进行右旋转;
  3. 如果左右子结点均为红色,进行颜色转换

10、红黑树的构造轨迹

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值