JAVA实践红黑树-小试牛刀

前言

第一感觉是和AVL树差别不是特别大,没有很直观的感受到效率的巨大提升,作为一个小小的强迫症患者,还是AVL树更好看。

不过讲道理,平衡被破坏次数相同情况下,红黑树的确少了那么一些旋转。。。

因为插入节点后平衡被破坏时,红黑树的会选择旋转或变色。
AVL树则只有旋转。

另外我发现其他的大神写法,跟我的有点差距。。。有心人可以帮我瞄一眼,我是不是哪里错了,在此先谢过了~~

另外一个参考网站、博客、PDF:
红黑树的可视化,插入、删除节点都有动画效果哦~
神奇的讲义,略的比较多,但就胜在简略
一个大神的博客,思路清晰,详细,非常值得参考

实现功能

插入
还有个伪删除。。。可以忽略,加个布尔变量的事。

不然咋叫小试牛刀呢(逃

参考

首先瞄一眼红黑树的性质

JAVA实践红黑树-小试牛刀_第1张图片

再看看长啥样
JAVA实践红黑树-小试牛刀_第2张图片

关于插入的那些事

JAVA实践红黑树-小试牛刀_第3张图片

JAVA实践红黑树-小试牛刀_第4张图片

JAVA实践红黑树-小试牛刀_第5张图片

JAVA实践红黑树-小试牛刀_第6张图片

JAVA实践红黑树-小试牛刀_第7张图片

JAVA实践红黑树-小试牛刀_第8张图片

JAVA实践红黑树-小试牛刀_第9张图片

JAVA实践红黑树-小试牛刀_第10张图片

JAVA实践红黑树-小试牛刀_第11张图片

JAVA实践红黑树-小试牛刀_第12张图片

JAVA实践红黑树-小试牛刀_第13张图片

JAVA实践红黑树-小试牛刀_第14张图片

JAVA实践红黑树-小试牛刀_第15张图片

再次汇总

JAVA实践红黑树-小试牛刀_第16张图片

代码实现

public class RBTree<T extends Comparable<T>> {

    public static void main(String[] args) {

        ///*
        int[] testNum = new int[]{15, 1, 3, 6, 8, 20, 22, 43, 67};
        RBTree fuck = new RBTree();
        for (int i = 0; i < testNum.length; i++) {
          fuck.insertNode(testNum[i]);
        }
        System.out.println(fuck.root.data);
        //*/
        /*
        RBTree fuck = new RBTree();
        fuck.insertNode('F');
        fuck.insertNode('G');
        fuck.insertNode('D');
        fuck.insertNode('B');
        fuck.insertNode('C');
        System.out.println(fuck.root.data);
        */
    }

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

    private TreeNode root;

    /**
     * 插入一个新的节点,插入完毕后符合红黑树性质
     *
     * @param data  需要插入的数据
     */
    public void insertNode(T data) {
        TreeNode curr;
        TreeNode parent = toTargetParent(data);
        if (parent == null) {
            curr = root = new TreeNode(data);
        } else {
            if (data.compareTo(parent.data) < 0) {
                curr = parent.left = new TreeNode(data);
                curr.parent = parent;
            } else {
                curr = parent.right = new TreeNode(data);
                curr.parent = parent;
            }
        }
        fixupTree(curr);
    }

    /**
     * 修复红黑树的不平衡状态
     *
     * @param node  新增节点
     */
    private void fixupTree(TreeNode node) {
        TreeNode parent = null, grandParent = null;
        boolean parentColor = false, uncleColor = false;
        if (node != root) {
            parent = node.parent;
            grandParent = parent.parent;
            parentColor = parent.color;
            uncleColor = getUncleColor(node);
        }
        //父节点为空表示其为根节点
        if (parent == null && node.color == RED) {
            node.color = BLACK;
        } else if (parentColor == RED && uncleColor == RED) {
            changeColor(grandParent);
            //再次判断根节点是否满足要求
            fixupTree(grandParent);
        } else if (parentColor == RED && uncleColor == BLACK) {
            dispatchRotation(grandParent, parent, node);
        }
    }

    /**
     * 判断属于哪种四种情况,LL、LR、RR、RL,使用正确的旋转
     *
     * @param grandParent   祖父节点
     * @param parent    父节点
     * @param child     新增节点
     */
    private void dispatchRotation(TreeNode grandParent, TreeNode parent, TreeNode child) {
        if (grandParent.left == parent) {
            if (parent.left == child) {
                rightRotation(grandParent);
            } else {
                leftRotation(parent);
                rightRotation(grandParent);
            }
        } else {
            if (parent.left == child) {
                rightRotation(parent);
                leftRotation(grandParent);
            } else {
                leftRotation(grandParent);
            }
        }
    }


    /**
     *  改变祖父节点以及两个子节点的颜色
     *
     * @param grandParent   传入新增节点的祖父
     */
    private void changeColor(TreeNode grandParent) {
        grandParent.color = RED;
        if (grandParent.left != null) {
            grandParent.left.color = BLACK;
        }
        if (grandParent.right != null) {
            grandParent.right.color = BLACK;
        }
    }

    /**
     * 返回叔叔节点的颜色
     *
     * @param node 一个节点
     * @return 其叔叔节点的颜色
     */
    private boolean getUncleColor(TreeNode node) {
        TreeNode parent = node.parent;
        //如果当前结点的祖父是空的,说明是其父节点是根节点
        return getBrotherColor(parent.parent == null ? node : parent);
    }

    /**
     * 返回兄弟节点的颜色
     *
     * @param child 传入节点
     * @return 返回兄弟节点的颜色
     */
    private boolean getBrotherColor(TreeNode child) {
        TreeNode parent = child.parent;
        if (parent.left == child && parent.right != null) {
            return parent.right.color;
        } else if (parent.right == child && parent.left != null) {
            return parent.left.color;
        } else {
            return BLACK;
        }
    }

    /**
     *  将传入的节点的右子节点提升为新的父节点,传入节点降为其右子节点
     *  注意颜色、父节点需要处理,务必要清除传入节点的右子节点,因为其已经被提升了父节点了。
     * @param curr  一个节点
     */
    private void leftRotation(TreeNode curr) {
        TreeNode tParent = curr.right;
        tParent.parent = curr.parent;
        tParent.color = BLACK;
        //新父节点的左子节点,放在传入节点的右边
        curr.right = tParent.left;
        if (tParent.left != null) {
            tParent.left.parent = curr;
        }
        //降为子节点前的数据整理
        curr.color = RED;
        curr.parent = tParent;
        tParent.left = curr;
        setChild(curr, tParent);
    }

    /**
     *  将传入的节点的左子节点提升为新的父节点,传入节点降为其右子节点
     *  注意颜色、父节点需要处理,务必要清除传入节点的左子节点,因为其已经被提升了父节点了。
     * @param curr  一个节点
     */
    private void rightRotation(TreeNode curr) {
        //新的父节点
        TreeNode tParent = curr.left;
        tParent.parent = curr.parent;
        tParent.color = BLACK;
        //新父节点的右子节点,放在传入节点的左边
        curr.left = tParent.right;
        if (tParent.right != null) {
            tParent.right.parent = curr;
        }
        //传入节点降为子节点前的数据整理
        curr.color = RED;
        curr.parent = tParent;
        tParent.right = curr;
        setChild(curr, tParent);
    }

    /**
     * 使旋转在树中生效
     *
     * @param roNode    被旋转的节点
     * @param newParent 被旋转之后的父节点
     */
    private void setChild(TreeNode roNode, TreeNode newParent) {
        TreeNode roNodeParent = newParent.parent;
        if (roNodeParent == null) {
            root = newParent;
        } else if (roNodeParent.left == roNode) {
            roNodeParent.left = newParent;
        } else {
            roNodeParent.right = newParent;
        }
    }

    /**
     *  调到data存放位置的父节点处
     * @param data  用于对比的数据
     * @return  data可存放处的父节点
     */
    private TreeNode toTargetParent(T data) {
        TreeNode curr = root;
        TreeNode parent = root;
        while (curr != null) {
            parent = curr;
            if (data.compareTo(curr.data) < 0) {
                curr = curr.left;
            } else {
                curr = curr.right;
            }
        }
        return parent;
    }

    /**
     * 内部节点
     */
    static class TreeNode<T extends Comparable<T>> {
        T data;
        boolean color;
        //伪删除
        boolean isDeleted;
        TreeNode left;
        TreeNode right;
        TreeNode parent;

        TreeNode(T data, boolean color) {
            this.data = data;
            this.color = color;
        }

        TreeNode(T data) {
            this.data = data;
            this.color = RED;
        }
    }
}

结果

8

经过验证,长这样!

JAVA实践红黑树-小试牛刀_第17张图片

END

你可能感兴趣的:(数据结构与算法)