红黑树数据结构讲解(附Java实现代码)

2-3查找树定义

1.任意空链接到根节点的路径长度都是相等的
2. 4-结点变换为3-结点时, 树的高度不会发生变化, 只有当根节点是临时的4-结点时, 分解根节点后, 树的高度+1
3.普通二叉查找树是自顶向下生长的, 2-3查找树的自底向上生长的
在这里插入图片描述
在这里插入图片描述
都是2-3查找树
(插入节点过程中产生的4-结点是临时的!)

红黑树定义

在满足2-3查找树的前提上, 使用对结点间链接的==“标记” == 以
颜色有两种:
红色 模拟2-3查找树中的3-结点
黑色 普通的结点链接形式

性质:

  1. 红链接均为左连接
    2.没有任何一个结点同时与两个红链接相连(4-结点不存在)
    3.任意空链接到根节点的路径经过相同的黑链接

这样, 红黑树能够在插入结点的同时保持美妙的平衡.
有了这些知识, 开始构建自己的红黑树吧!

左旋和右旋

当某个结点的左子结点为黑色,右子结点为红色,此时需要左旋.
比如下图中, 插入一个值为50的结点
在这里插入图片描述

通过左旋. 我们能使只有左链接为红色,
但是
会出现下面的情况:

在这里插入图片描述
这违反了红黑树的规则1, 所以我们仍要操作, 那么进行右旋
|
|
|
在这里插入图片描述
但是发现, 还是违反了规则2
所以继续操作

颜色反转

上述的操作产生了有两个红链接的结点(相当于二叉树中的4-结点), 此时, 我们需要对此结点继续进行操作, 使其满足规则2.
先看看下面这张图
插入S后, 形成了AES(4-结点), 然后对4-结点进行分解
在这里插入图片描述
和这张图
在这里插入图片描述
此时再来看看这张图: 是不是有相同的地方(把它看成上面的4-结点)
在这里插入图片描述
现在继续对这个结点进行操作:
在这里插入图片描述
看到这里, 你可能有些疑惑: 怎么就是把两个红链接变为黑色呢?
别急, 看下面

假如有一个50元素的结点时
在这里插入图片描述
结果不一样了, 这是因为我们规定: 根结点的链接永远指向自己, 根链接永远为黑色
看到这里, 代码要实现的就是找到要插入元素的位置, 并放置该结点, 并先后进行**(左旋, 右旋, 颜色反转)------(如果必要的话)** 就能保持红黑树的平衡了
代码:

Java实现代码

package cn.datastructure.structure.tree;

/**
 * @author 悠一木碧
 * 红黑树实现:
 * 基于了2-3查找树的思想:
 * 任意空链接到根节点的路径长度都是相等的
 * 4-结点变换为3-结点时, 树的高度不会发生变化, 只有当根节点是临时的4-结点时, 分解根节点后, 树的高度+1
 * 普通二叉查找树是自顶向下生长的, 2-3查找树的自底向上生长的
 * 且:
 * 红链接均为左连接
 * 没有任何一个结点同时与两个红链接相连
 * 任意空链接到根节点的路径经过相同的黑链接
 */
public class RedBlackTree<Key extends Comparable<Key>, Value> {
    
    
    private Node root;
    private int size;
    private final boolean RED = true;
    private final boolean BLACK = false;

    private class Node{
    
    
        public Key key;
        public Value value;
        public Node left;
        public Node right;
//        用来标识父节点指向自己链接的颜色
        public boolean color;

        public Node(Key key, Value value, Node left, Node right, boolean color) {
    
    
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
            this.color = color;
        }

        public Node() {
    
    
        }

    }


//  将根链接的颜色永远设置为黑色
    public void put(Key key, Value value){
    
    
        root = put(root, key, value);
        this.root.color = BLACK;
    }

//  在node结点下完成插入操作, 是个递归方法
    private Node put(Node node, Key key, Value value){
    
    
        if(null == node){
    
    
            size++;
            return new Node(key, value, null, null, BLACK);
        }
        if(key.compareTo(node.key) < 0){
    
    
            node.left = put(node.left, key, value);
        } else if(key.compareTo(node.key) > 0){
    
    
            node.right = put(node.right, key, value);
        } else{
    
    
            node.value = value;
        }

        if(isRed(node.right) && !isRed(node.left)){
    
    
            rotateLeft(node);
        }
        if(isRed(node.left) && isRed(node.left.left)){
    
    
            rotateRight(node);
        }
        if(isRed(node.left) && isRed(node.right)){
    
    
            colorInversion(node);
        }
        return node;
    }

    /**
     * 左旋操作,
     * @param head
     */
    private Node rotateLeft(Node head){
    
    
        Node rightSon = head.right;
        head.right = rightSon.left;
        rightSon.left = head;
        rightSon.color = head.color;
        head.color = RED;
        return rightSon;
    }

    /**
     * 右旋操作
     * @param head
     * @return
     */
    private Node rotateRight(Node head){
    
    
        Node leftSon = head.left;
        head.left = leftSon.right;
        leftSon.right = head;
        leftSon.color = head.color;
        head.color = RED;
        return leftSon;
    }

    /**
     * 空链接默认为黑色
     * @param node
     * @return
     */
    private boolean isRed(Node node){
    
    
        if(null == node){
    
    
            return false;
        }
        return node.color == RED;
    }


    /**
     * 相当于拆分掉4-结点, 在红黑树中, 临时的4-结点相当于当前结点的左右链接都是红色
     * @param node
     */
    private void colorInversion(Node node){
    
    
        node.color = RED;
        node.left.color = BLACK;
        node.right.color = BLACK;
    }




    public Value get(Key key){
    
    
        return get(root, key);
    }

    private Value get(Node node, Key key){
    
    
        if(null == node){
    
    
            return null;
        }

        int res = key.compareTo(node.key);

        if(res > 0){
    
    
            return get(node.right, key);
        } else if(res < 0){
    
    
            return get(node.left, key);
        } else{
    
    
            return node.value;
        }
    }



    public int size(){
    
    
        return size;
    }

}

猜你喜欢

转载自blog.csdn.net/Valishment/article/details/109319469