Java红黑树

https://www.bilibili.com/video/BV1UJ411J7CU?t=2361&p=4


观后感 = 理解 + 实践:

/**
 * @author alya
 */
public class RedBlackTree<K extends Comparable<K>, V> {

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

    private TreeNode<K, V> root;

    public TreeNode<K, V> getRoot() {
        return root;
    }

    static class TreeNode<K extends Comparable<K>, V> {
        private TreeNode<K, V> parent;
        private TreeNode<K, V> left;
        private TreeNode<K, V> right;
        private boolean color;
        private K key;
        private V value;

        public TreeNode() {
        }

        public TreeNode(TreeNode<K, V> parent, TreeNode<K, V> left, TreeNode<K, V> right, boolean color, K key, V value) {
            this.parent = parent;
            this.left = left;
            this.right = right;
            this.color = color;
            this.key = key;
            this.value = value;
        }

        public TreeNode<K, V> getParent() {
            return parent;
        }

        public void setParent(TreeNode<K, V> parent) {
            this.parent = parent;
        }

        public TreeNode<K, V> getLeft() {
            return left;
        }

        public void setLeft(TreeNode<K, V> left) {
            this.left = left;
        }

        public TreeNode<K, V> getRight() {
            return right;
        }

        public void setRight(TreeNode<K, V> right) {
            this.right = right;
        }

        public boolean isColor() {
            return color;
        }

        public void setColor(boolean color) {
            this.color = color;
        }

        public K getKey() {
            return key;
        }

        public void setKey(K key) {
            this.key = key;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }
    }

    private TreeNode<K, V> parentOf(TreeNode<K, V> node) {
        if (node != null) {
            return node.parent;
        }
        return null;
    }

    private boolean isRed(TreeNode<K, V> node) {
        if (node != null) {
            return node.color == RED;
        }
        return false;
    }

    private boolean isBlack(TreeNode<K, V> node) {
        if (node != null) {
            return node.color == BLACK;
        }
        return false;
    }

    private void setBlack(TreeNode<K, V> node) {
        if (node != null) {
            node.color = BLACK;
        }
    }

    private void setRed(TreeNode<K, V> node) {
        if (node != null) {
            node.color = RED;
        }
    }

    public void inOrderPrint() {
        inOrderPrint(this.root);
    }

    private void inOrderPrint(TreeNode<K, V> node) {
        if (node != null) {
            inOrderPrint(node.left);
            System.out.println("key: " + node.key + ", value: " + node.value + ", color: " + (node.color == RED ? "red" : "black"));
            inOrderPrint(node.right);
        }
    }

    public void preOrderPrint() {
        preOrderPrint(this.root);
    }

    private void preOrderPrint(TreeNode<K, V> node) {
        if (node != null) {
            System.out.println("key: " + node.key + ", value: " + node.value + ", color: " + (node.color == RED ? "red" : "black"));
            preOrderPrint(node.left);
            preOrderPrint(node.right);
        }
    }

    public void afterOrderPrint() {
        afterOrderPrint(this.root);
    }

    private void afterOrderPrint(TreeNode<K, V> node) {
        if (node != null) {
            afterOrderPrint(node.left);
            afterOrderPrint(node.right);
            System.out.println("key: " + node.key + ", value: " + node.value + ", color: " + (node.color == RED ? "red" : "black"));
        }
    }

    /**
     *     root                                  root
     *      |                                     |
     *      p                                     r
     *    /  \                                  /  \
     *   l    r         <<< p为支点左旋 <<<     p    rr
     *      /  \                             /  \
     *     rl  rr                           l   rl
     *
     * @param p 旋转支点
     */
    private void leftRotate(TreeNode<K, V> p) {

        TreeNode<K, V> r = p.right;
        TreeNode<K, V> rl = r.left;

        // p的右子节点指向为rl
        p.right = rl;

        // rl的父节点指向p
        if (rl != null) {
            rl.parent = p;
        }

        // 如果p有父节点, r的父节点指向p的父节点,当p在左边r在左边,p在右边则r在右边
        TreeNode<K, V> pp = p.parent;
        if (pp != null) {
            r.parent = pp;
            if (p == pp.left) {
                pp.left = r;
            } else {
                pp.right = r;
            }
        } else {
            // p为根节点,那么r就是根节点
            this.root = r;
            r.parent = null;
        }

        // p的父节点为r,r的左子节点为p
        p.parent = r;
        r.left = p;
    }

    /**
     *       pp                               pp
     *       |                                |
     *       p                                l
     *     /  \                             /  \
     *    l    r       >>> p为支点右旋 >>>  ll   p
     *  /  \                                  /  \
     * ll  lr                                lr   r
     *
     * @param p 旋转支点
     */
    private void rightRotate(TreeNode<K, V> p) {
        TreeNode<K, V> l = p.left;
        TreeNode<K, V> lr = l.right;

        // p的左子节点指向lr
        p.left = lr;

        // lr不是空节点,lr的父节点指向p
        if (lr != null) {
            lr.parent = p;
        }

        // 如果p有父节点,p在左边时l在在左边,右边同理,l的父节点指向p的父节点;
        TreeNode<K, V> pp = p.parent;
        if (pp != null) {
            l.parent = pp;
            if (p == pp.left) {
                pp.left = l;
            } else {
                pp.right = l;
            }
        } else {
            this.root = l;
            l.parent = null;
        }

        p.parent = l;
        l.right = p;
    }

    public void put(K key, V value) {
        TreeNode<K, V> node = new TreeNode<>();
        node.setKey(key);
        node.setValue(value);
        node.setColor(RED);
        put(node);
    }

    private void put(TreeNode<K, V> node) {
        TreeNode<K, V> parent = null;
        TreeNode<K, V> currentNode = this.root;
        // 找位置
        while (currentNode != null) {
            parent = currentNode;
            int i = node.key.compareTo(currentNode.key);
            if (i > 0) {
                // 在右子树
                currentNode = currentNode.right;
            } else if (i == 0) {
                // 替换值
                currentNode.setValue(node.getValue());
                return;
            } else {
                // 在左子树
                currentNode = currentNode.left;
            }
        }
        // 在左边还是右边
        node.parent = parent;
        if (parent != null) {
            int i = node.key.compareTo(parent.key);
            if (i > 0) {
                // 在右子树
                parent.right = node;
            } else {
                // 在左子树
                parent.left = node;
            }
        } else {
            this.root = node;
        }
        // 数平衡修复
        balanceTree(node);
    }

    /**
     * 情景1:空树 -> 插入节点变黑并设置为根节点。
     * 情景2:插入节点已存在 -> 替换值。
     * 情景3:插入节点的父节点为黑色 -> 不做处理。
     *
     * 情景4:插入节点的父节点为红色;(由于根节点为黑色,所以父节点为红色时,必定存在爷爷节点)
     *  |--- 情景4.1:叔叔节点存在并且为红色,那么爷爷节点为黑色 -> 把爷爷节点变成红色,父节点、叔叔节点变成黑色,以爷爷节点为当前节点进行下一步处理。
     *  |--- 情景4.2:叔叔节点不存在或者为黑色,父节点为爷爷节点的左子节点;
     *      |--- 情景4.2.1:插入节点为左子节点,形成LL双红情况 -> 将父节点变黑,爷爷节点变红,以爷爷节点为支点进行右旋。
     *      |--- 情景4.2.2:插入节点为右子节点,形成LR双红情况 -> 以父节点为支点左旋,结果为情景4.2.1,以父节点为当前节点进行下一步处理。
     *  |--- 情景4.3:叔叔节点不存在或者为黑色,父节点为爷爷节点的右子节点;
     *      |--- 情景4.3.1:插入节点为左子节点,形成RL双红情况 -> 将父节点变黑,爷爷节点变红,以爷爷节点为支点进行左旋。
     *      |--- 情景4.3.2:插入节点为左子节点,形成RR双红情况 -> 以父节点为支点右旋,结果为情景4.3.1,以父节点为当前节点进行下一步处理。
     *
     * @param node node
     */
    private void balanceTree(TreeNode<K, V> node) {
        setBlack(this.root);
        
        TreeNode<K, V> parent = parentOf(node);
        TreeNode<K, V> grandpa = parentOf(parent);

        if (parent != null && isRed(parent)) {
            // 情景4:插入节点的父节点为红色;(由于根节点为黑色,所以父节点为红色时,必定存在爷爷节点)
            TreeNode<K, V> uncle = null;
            if (parent == grandpa.left) {
                uncle = grandpa.right;
                // 情景4.1:叔叔节点存在并且为红色,那么爷爷节点为黑色 -> 把爷爷节点变成红色,父节点、叔叔节点变成黑色,以爷爷节点为当前节点进行下一步处理。
                if (uncle != null && isRed(uncle)) {
                    setRed(grandpa);
                    setBlack(parent);
                    setBlack(uncle);
                    balanceTree(grandpa);
                    return;
                }
                // 情景4.2:叔叔节点不存在或者为黑色,父节点为爷爷节点的左子节点;
                if (uncle == null || isBlack(uncle)) {
                    // 情景4.2.1:插入节点为左子节点,形成LL双红情况 -> 将父节点变黑,爷爷节点变红,以爷爷节点为支点进行右旋。
                    if (node == parent.left) {
                        setBlack(parent);
                        setRed(grandpa);
                        rightRotate(grandpa);
                    }
                    // 情景4.2.2:插入节点为右子节点,形成LR双红情况,结果为情景4.2.1,以父节点为当前节点进行下一步处理。
                    if (node == parent.right) {
                        leftRotate(parent);
                        balanceTree(parent);
                        return;
                    }
                }
            } else {
                uncle = grandpa.left;
                // 情景4.1:叔叔节点存在并且为红色,那么爷爷节点为黑色 -> 把爷爷节点变成红色,父节点、叔叔节点变成黑色,以爷爷节点为当前节点进行下一步处理。
                if (uncle != null && isRed(uncle)) {
                    setRed(grandpa);
                    setBlack(parent);
                    setBlack(uncle);
                    balanceTree(grandpa);
                    return;
                }
                // 情景4.3:叔叔节点不存在或者为黑色,父节点为爷爷节点的右子节点;
                if (uncle == null || isBlack(uncle)) {
                    // 情景4.3.1:插入节点为左子节点,形成RL双红情况 -> 将父节点变黑,爷爷节点变红,以爷爷节点为支点进行左旋。
                    if (node == parent.left) {
                        rightRotate(parent);
                        balanceTree(parent);
                        return;
                    }
                    // 情景4.3.2:插入节点为左子节点,形成RR双红情况,结果为情景4.3.1,以父节点为当前节点进行下一步处理。
                    if (node == parent.right) {
                        setBlack(parent);
                        setRed(grandpa);
                        leftRotate(grandpa);
                    }
                }
            }
        }
    }

    public TreeNode<K, V> getNode(K key) {
        return getVal(key);
    }

    public V get(K key) {
        TreeNode<K, V> node = getVal(key);
        return node == null ? null : node.getValue();
    }

    private TreeNode<K, V> getVal(K key) {
        TreeNode<K, V> node = this.root;
        while (node != null) {
            int i = key.compareTo(node.key);
            if (i > 0) {
                node = node.right;
            } else if (i == 0) {
                return node;
            } else {
                node = node.left;
            }
        }
        return null;
    }

    public int size() {
        return getSize(this.root);
    }

    private int getSize(TreeNode<K, V> node) {
        if (node == null) {
            return 0;
        }
        int ls = getSize(node.left);
        int rs = getSize(node.right);
        return ls + rs + 1;
    }

}

好的嘞可以去看HashMap的红黑树了~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的红黑树实现主要是通过对节点进行变色和旋转来维持其特性。具体实现可以参考以下步骤: 1.定义红黑树节点类,包括节点值、颜色、左右子节点等属性。 2.定义红黑树类,包括根节点、插入节点、删除节点等方法。 3.在插入节点时,根据其父节点和父节点的兄弟节点进行变色和旋转,以维持红黑树的特性。 4.在删除节点时,同样需要进行变色和旋转,以保证删除后的树仍然是一颗红黑树。 以下是一个简单的Java红黑树实现示例: ```java public class RBNode<T extends Comparable<T>> { boolean color;//颜色 T key;//关键字(键值) RBNode<T> left;//左子节点 RBNode<T> right;//右子节点 RBNode<T> parent;//父节点 public RBNode(boolean color, T key, RBNode<T> parent, RBNode<T> left, RBNode<T> right) { this.color = color; this.key = key; this.parent = parent; this.left = left; this.right = right; } } public class RBTree<T extends Comparable<T>> { private RBNode<T> root;//根节点 //插入节点 public void insert(T key) { RBNode<T> node = new RBNode<T>(false, key, null, null, null); if (node != null) { insert(node); } } //插入节点 private void insert(RBNode<T> node) { RBNode<T> current = null;//当前节点 RBNode<T> x = this.root;//从根节点开始查找 //查找插入位置 while (x != null) { current = x; if (node.key.compareTo(x.key) < 0) { x = x.left; } else { x = x.right; } } node.parent = current; if (current != null) { if (node.key.compareTo(current.key) < 0) { current.left = node; } else { current.right = node; } } else { this.root = node; } //修正红黑树 insertFixUp(node); } //修正红黑树 private void insertFixUp(RBNode<T> node) { RBNode<T> parent, gparent;//父节点和祖父节点 //需要修正的条件:父节点存在,且父节点的颜色是红色 while (((parent = parentOf(node)) != null) && isRed(parent)) { gparent = parentOf(parent);//祖父节点 //父节点是祖父节点的左子节点 if (parent == gparent.left) { RBNode<T> uncle = gparent.right;//叔叔节点 //case1:叔叔节点也是红色 if ((uncle != null) && isRed(uncle)) { setBlack(parent); setBlack(uncle); setRed(gparent); node = gparent; continue; } //case2:叔叔节点是黑色,且当前节点是右子节点 if (node == parent.right) { RBNode<T> tmp; leftRotate(parent); tmp = parent; parent = node; node = tmp; } //case3:叔叔节点是黑色,且当前节点是左子节点 setBlack(parent); setRed(gparent); rightRotate(gparent); } else {//父节点是祖父节点的右子节点 RBNode<T> uncle = gparent.left;//叔叔节点 //case1:叔叔节点也是红色 if ((uncle != null) && isRed(uncle)) { setBlack(parent); setBlack(uncle); setRed(gparent); node = gparent; continue; } //case2:叔叔节点是黑色,且当前节点是左子节点 if (node == parent.left) { RBNode<T> tmp; rightRotate(parent); tmp = parent; parent = node; node = tmp; } //case3:叔叔节点是黑色,且当前节点是右子节点 setBlack(parent); setRed(gparent); leftRotate(gparent); } } setBlack(this.root);//将根节点设为黑色 } //左旋 private void leftRotate(RBNode<T> x) { RBNode<T> y = x.right; x.right = y.left; if (y.left != null) { y.left.parent = x; } y.parent = x.parent; if (x.parent == null) { this.root = y; } else { if (x.parent.left == x) { x.parent.left = y; } else { x.parent.right = y; } } y.left = x; x.parent = y; } //右旋 private void rightRotate(RBNode<T> y) { RBNode<T> x = y.left; y.left = x.right; if (x.right != null) { x.right.parent = y; } x.parent = y.parent; if (y.parent == null) { this.root = x; } else { if (y == y.parent.right) { y.parent.right = x; } else { y.parent.left = x; } } x.right = y; y.parent = x; } //获取节点的父节点 private RBNode<T> parentOf(RBNode<T> node) { return node != null ? node.parent : null; } //判断节点是否是红色 private boolean isRed(RBNode<T> node) { return (node != null) && node.color; } //设置节点为红色 private void setRed(RBNode<T> node) { if (node != null) { node.color = true; } } //设置节点为黑色 private void setBlack(RBNode<T> node) { if (node != null) { node.color = false; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值