紅黑樹底層實(shí)現(xiàn)原理分析及JAVA代碼實(shí)現(xiàn)

------------ 本文來自 阿P官方博客
------------ 在線測(cè)試紅黑樹:紅黑樹在線測(cè)試

一、紅黑樹

    自平衡二叉查找樹(Binary Search Tree)
    二叉查找樹:
        基于二叉樹
            左子樹小于根,右子樹大于根
            缺點(diǎn):如果選錯(cuò)根節(jié)點(diǎn),整個(gè)樹就不再平衡
    特點(diǎn)
        所有節(jié)點(diǎn)非紅即黑
        根節(jié)點(diǎn)一定是黑色
        紅節(jié)點(diǎn)的子節(jié)點(diǎn)一定是黑色
        最低層的葉子節(jié)點(diǎn)一定是黑色
        從根節(jié)點(diǎn)到任意葉子節(jié)點(diǎn)經(jīng)歷過的黑色節(jié)點(diǎn)一定相同
        新增的節(jié)點(diǎn)顏色一定是紅色節(jié)點(diǎn)
    紅黑樹時(shí)間復(fù)雜度:O(logN) 與二分查找法一致
        第一次查找數(shù)量 n/2
        第二次查找數(shù)量 n/2/2
        第三次查找數(shù)量 n/2/2/2
        …...
        第m次查找數(shù)量 n/(2^m)
        由此我們可以得知時(shí)間復(fù)雜度=logN

二、紅黑樹修正(遵循以下步驟進(jìn)行修正)

    當(dāng)前節(jié)點(diǎn)為紅,父節(jié)點(diǎn)為紅,并且叔父節(jié)點(diǎn)為紅或?yàn)榭?        父節(jié)點(diǎn)、叔父節(jié)點(diǎn)涂黑,祖父節(jié)點(diǎn)涂紅。對(duì)祖父節(jié)點(diǎn)繼續(xù)操作
    當(dāng)前節(jié)點(diǎn)為紅且是右子葉,父節(jié)點(diǎn)為紅,并且叔父節(jié)點(diǎn)為黑
        以當(dāng)前節(jié)點(diǎn)為軸,進(jìn)行左旋
    當(dāng)前節(jié)點(diǎn)為紅且是左子葉,父節(jié)點(diǎn)為紅,并且叔父節(jié)點(diǎn)為黑
        父節(jié)點(diǎn)涂黑,祖父節(jié)點(diǎn)涂紅,以父節(jié)點(diǎn)為軸,進(jìn)行右旋

三、紅黑樹JAVA實(shí)現(xiàn)類

package RBTree;

/**
 * 紅黑樹
 *
 */
public class RBTreeDemo<T extends Comparable<T>> {
    
    Node root;//根節(jié)點(diǎn)
    Node min;//最左節(jié)點(diǎn)
    Node max;//最右節(jié)點(diǎn)
    
    Boolean RED = true;
    Boolean BLACK = false;
    /**
     * 新增
     * @param val
     */
    public void add(T val)
    {
        if (this.root == null) {
            //根節(jié)點(diǎn)為黑色
            this.root = new Node<T>(val, this.BLACK, null, null, null);
            return;
        }
        Node node = this.root;
        //當(dāng)前節(jié)點(diǎn)
        Node current = new Node<T>(val, this.RED, null, null, null);
        //遍歷樹,進(jìn)行插入
        while (true) {
            if (val.compareTo((T) node.val) > 0) {//放右子節(jié)點(diǎn)
                if (node.right == null) {
                    node.right = current;
                    current.parent = node;
                    break;
                }
                node=node.right;
            } else {//放左子節(jié)點(diǎn)
                if (node.left == null) {
                    node.left = current;
                    current.parent = node;
                    break;
                }
                node=node.left;
            }
        }
        //插入完進(jìn)行自平衡
        fixUp(current);
    }
    /**
     * 自平衡
     */
    public void fixUp(Node node)
    {
        //當(dāng)前節(jié)點(diǎn)沒父節(jié)點(diǎn),則涂黑
        if (node.parent == null) {
            node.color = this.BLACK;
            this.root = node;
            return;
        }
        //當(dāng)前節(jié)點(diǎn)沒有祖父節(jié)點(diǎn)
        if (node.parent.parent == null) {
            return;
        }
        //叔父節(jié)點(diǎn) 可以為空
        Node uncleNode = this.getUncleNode(node);
        //當(dāng)前節(jié)點(diǎn)為紅,且父節(jié)點(diǎn)為紅
        if (node.color == this.RED && node.parent.color == this.RED) {
            //叔父節(jié)點(diǎn)為空或者為紅,就進(jìn)行涂色
            if (uncleNode == null || uncleNode.color == this.RED) {
                node.parent.color = this.BLACK;
                if (uncleNode != null) {
                    uncleNode.color=this.BLACK;
                }
                node.parent.parent.color = this.RED;
                this.fixUp(node.parent.parent);
            } else if (uncleNode.color == this.BLACK) {
                //自己是左子葉
                if (node.parent.left.equals(node)) {
                    this.right(node);
                    this.fixUp(node.parent);//右旋后,修改當(dāng)前節(jié)點(diǎn)顏色
                } else {//自己是右子葉
                    this.left(node);
                    this.fixUp(node.left);//曾經(jīng)的父節(jié)點(diǎn)
                }
            }
        }
    }
    /**
     * 叔父節(jié)點(diǎn),可以為空
     * @param node
     * @return
     */
    private Node getUncleNode(Node node) {
        Node uncleNode= node.parent.parent.left;
        if (uncleNode == null || node.parent.equals(uncleNode)) {
            uncleNode = node.parent.parent.right;
        }
        return uncleNode;
    }
    /**
     * 當(dāng)前結(jié)點(diǎn)為紅,且處于右子葉上。父節(jié)點(diǎn)為紅,叔父節(jié)點(diǎn)為黑或空時(shí)。以當(dāng)前節(jié)點(diǎn)為軸進(jìn)行左旋
     * 當(dāng)前節(jié)點(diǎn)的祖父節(jié)點(diǎn),變成自己的父節(jié)點(diǎn)
     * 當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn),變成自己的左節(jié)點(diǎn)
     * 當(dāng)前節(jié)點(diǎn)的左節(jié)點(diǎn),變成當(dāng)前右節(jié)點(diǎn)的右節(jié)點(diǎn)
     */
    private void left(Node node) {
        Node parent = node.parent;
        Node left = node.left;
        Node pParent = node.parent.parent;
        //祖父節(jié)點(diǎn)
        pParent.left = node;
        //父節(jié)點(diǎn)
        parent.parent = node;
        parent.right = left;
        //左節(jié)點(diǎn)
        left.parent = parent;
        //當(dāng)前節(jié)點(diǎn)
        node.parent = pParent;
        node.left = parent;
    }
    /**
     * 當(dāng)前結(jié)點(diǎn)為紅,且處于左子葉上。父節(jié)點(diǎn)為紅,叔父節(jié)點(diǎn)為黑時(shí)。以父節(jié)點(diǎn)為軸進(jìn)行右旋
     */
    private void right(Node node) {
        Node parent = node.parent;
        Node right = parent.right;
        Node pParent = node.parent.parent;
        Node ppParent = node.parent.parent.parent;
        //涂色
        pParent.color = this.RED;
        parent.color = this.BLACK;
        if (ppParent != null) {
            //祖祖父節(jié)點(diǎn)
            if (ppParent.right.equals(pParent)) {
                ppParent.right = parent;
            } else {
                ppParent.left = parent;
            }
        }
        //祖父節(jié)點(diǎn)
        pParent.left = right;
        pParent.parent=parent;
        //父節(jié)點(diǎn)
        parent.right = pParent;
        parent.parent = ppParent;
        //右子節(jié)點(diǎn)
        right.parent = pParent;
    }
    /**
     * 前序遍歷 從根開始遍歷
     */
    private String preOrder(Node node) {
        if (node == null) {
            return null;//如果左側(cè)樹遍歷完成,返回null
        }
        String strLeft = this.preOrder(node.left);
        if (strLeft == null) {
            strLeft="";
        }
        String strRight = this.preOrder(node.right);
        if (strRight == null) {
            strRight="";
        }
        return strLeft + node.toString() + strRight;
    }
    @Override
    public String toString() {
        //前序遍歷
        return preOrder(this.root);
    }
    /**
     * 結(jié)點(diǎn)類
     */
    private class Node<T>{
        public T val;
        public Boolean color;//紅為true
        public Node left;
        public Node right;
        public Node parent;
        public Node(T val, Boolean color, Node left, Node right, Node parent) {
            super();
            this.val = val;
            this.color = color;
            this.left = left;
            this.right = right;
            this.parent = parent;
        }
        @Override
        public String toString() {
            String left = "-";
            String right = "-";
            if (this.left != null) {
                left = this.left.val.toString();
            }
            if (this.right != null) {
                right =  this.right.val.toString();
            }
            return "[" + left + ", "+this.val.toString() + ", " + right +", "+ getColorName(this.color) + "]";
        }
        private String getColorName(Boolean color) {
            return color == true? "紅" : "黑";
        }
        @Override
        public boolean equals(Object obj) {
            Node obj1 = (Node)obj;
            return obj1.val == this.val;
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 01.原則 昨天早上坐車的時(shí)候我還在和胖說,這邊的樹好奇怪啊,冬天樹葉也沒有全部枯黃掉落,春天它也沒有重新發(fā)芽,就...
    怡采在成長(zhǎng)閱讀 161評(píng)論 0 1
  • 老伴的日歷本記事 由春寫到冬 字跡密密麻麻 他將一頁頁折疊在兩側(cè) 立于窗臺(tái) 猶如一只蝴蝶落在窗口 這只日歷蝶羽翼豐...
    寒樺閱讀 368評(píng)論 2 10
  • 前兩天和一個(gè)朋友吃飯,不知道怎么說的就說到他女朋友上去了。他向我抱怨現(xiàn)任女友怎么樣怎么樣不好,“飯都不會(huì)做,蛋炒飯...
    念永恒閱讀 206評(píng)論 4 1
  • 很想念過去的日子 卻又不知道想念過去的什么日子 就像有一片葉子 需要悄悄靠近 靠近 很想念過去的日子 卻又...
    喬棪閱讀 432評(píng)論 3 7
  • idea 下,spring boot項(xiàng)目啟動(dòng)的時(shí)候報(bào)錯(cuò)Circular placeholder reference...
    xiao碼閱讀 8,733評(píng)論 0 1

友情鏈接更多精彩內(nèi)容