JAVA實現紅黑樹的刪除

背景:自學紅黑樹
開發語言:JAVA
本片內容:用java實現紅黑樹的刪除php

紅黑樹的由來(節選自百度百科)

   紅黑樹是在1972年由Rudolf Bayer發明的,當時被稱爲平衡二叉B樹(symmetric binary B-trees)。後來,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改成現在的「紅黑樹」。
   紅黑樹是一種特化的AVL樹(平衡二叉樹),都是在進行插入和刪除操做時經過特定操做保持二叉查找樹的平衡,從而得到較高的查找性能。
   它雖然是複雜的,但它的最壞狀況運行時間也是很是良好的,而且在實踐中是高效的: 它能夠在O(log n)時間內作查找,插入和刪除,這裏的n 是樹中元素的數目。java

紅黑樹與AVL樹的使用區別

增長和刪除,紅黑樹效率高;查詢,AVL樹效率高app

紅黑樹的特性

一、每一個節點的顏色是紅色或者黑色
二、根節點是黑色
三、空葉子節點是黑色
四、紅色節點的子節點必定是黑色
五、從任意節點開始到葉子節點結束,所通過的黑色節點個數必定是相同的性能

用代碼實現紅黑樹的刪除

紅黑樹節點代碼

package com.blueice.hello.BRTree;

/**
 * @FileName: BRNode
 * @Description: TODO(紅黑樹節點)
 * @Author: shaoz
 * @Date: 2021/7/8 10:43
 * @Copyright: 2021 www.***.com.cn  All rights reserved.
 * 注意:本內容僅限於***內部傳閱,禁止外泄以及用於其餘的商業目的
 */

public class BRNode {

    BRNode parent;

    TreeColor treeColor;

    BRNode left;

    BRNode right;

    int value;

    public BRNode(int value) {
        this.value = value;
        this.parent = null;
        this.left = null;
        this.right = null;
        this.treeColor = TreeColor.RED;
    }
}

紅黑樹的顏色

package com.blueice.hello.BRTree;

/**
 * @FileName: TreeColor
 * @Description: TODO(紅黑樹的顏色)
 * @Author: shaoz
 * @Date: 2021/7/8 15:23
 * @Copyright: 2021 www.***.com.cn  All rights reserved.
 * 注意:本內容僅限於***內部傳閱,禁止外泄以及用於其餘的商業目的
 */

public enum TreeColor {
    /**
     * 紅黑樹的顏色
     */

    BLACK("黑色"),RED("紅色");

    private String color;

    TreeColor(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }
}

紅黑樹的刪除

package com.blueice.hello.BRTree;

/**
 * @FileName: BRTree
 * @Description: TODO(紅黑樹)
 * @Author: shaoz
 * @Date: 2021/7/8 11:14
 * @Copyright: 2021 www.***.com.cn  All rights reserved.
 * 注意:本內容僅限於***內部傳閱,禁止外泄以及用於其餘的商業目的
 */

public class BRTree {

    BRNode root;

    public BRTree(int value) {
        this.root = new BRNode(value);
        this.root.treeColor = TreeColor.BLACK;
    }
    /**
     * 刪除紅黑樹中的值
     * @param value 要刪除的值
     */

    public void remove(int value) {
        BRNode curNode = root;
        while (curNode != null) {
            if (value == curNode.value) {
                removeNode(curNode);
                break;
            } else if (value > curNode.value) {
                curNode = curNode.right;
            } else {
                curNode = curNode.left;
            }
        }
    }

    /**
     * 刪除節點
     * @param curNode 要刪除的節點
     */

    private void removeNode(BRNode curNode) {
        /* 刪除節點後的替換節點 */
        BRNode replaceNode = null;

        /* 有2個子節點:找到後繼節點,繼續遞歸(只會遞歸一次,由於後繼節點確定沒有兩個非空子節點) */
        if (null != curNode.left && null != curNode.right) {
            for (replaceNode = curNode.right; null != replaceNode.left; replaceNode = replaceNode.left){};        
            curNode.value = replaceNode.value;
            removeNode(replaceNode);
        /* 沒有子節點 */
        } else if (null == curNode.left && null == curNode.right) {
            /* 當前節點是根節點,直接把紅黑樹置空 */
            if (null == curNode.parent) {
                this.root = null;
                return;
            }
            /* 當前節點顏色爲紅色:直接刪除 */
            if (TreeColor.RED == curNode.treeColor) {
                if (curNode == curNode.parent.left) {
                    curNode.parent.left = null;
                } else {
                    curNode.parent.right = null;
                }
            /* 當前節點爲黑色,進行刪除平衡操做 */
            } else {
                /* 刪掉當前節點 */
                BRNode parNode = curNode.parent;
                BRNode broNode;
                if (curNode == parNode.left) {
                    parNode.left = null;
                    broNode = parNode.right;
                } else {
                    parNode.right = null;
                    broNode = parNode.left;
                }
                /* 進行刪除平衡操做 */
                removeFixUp(parNode, broNode);
            }
        /* 有1個子節點:必定是黑-紅,刪掉當前節點,把紅色子節點放到當前位置,並染爲黑色 */
        } else {
            BRNode curParent = curNode.parent;
            BRNode sonNode;
            if (null != curNode.left) {
                sonNode = curNode.left;
            } else {
                sonNode = curNode.right;
            }
            sonNode.parent = curParent;
            if (null != curParent) {
                if (curNode == curParent.left) {
                    curParent.left = sonNode;
                } else {
                    curParent.right = sonNode;
                }
            } else {
                sonNode.treeColor = TreeColor.BLACK;
                this.root = sonNode;
            }
            sonNode.treeColor = TreeColor.BLACK;        
        }
    }

    /**
     * 紅黑樹刪除平衡操做(被刪除節點爲黑色,而且子節點全爲NIL)
     * @param parNode 父節點
     * @param broNode 兄弟節點
     */

    private void removeFixUp(BRNode parNode, BRNode broNode) {
        /*   <1> 當前節點爲根節點
        //   <2> 兄弟節點是黑色
        //     [1] 兄子節點全爲NIL(全黑)
        //       {1} 父紅
        //       {2} 父黑
        //     [2] 兄子節點不全黑
        //       {1} 兄在左,兄左子節點紅色
        //       {2} 兄在右,兄右子節點紅色
        //       {3} 兄在左,兄左子節點黑色
        //       {4} 兄在右,兄右子節點黑色
        //   <3> 兄弟節點是紅色
        //     [1] 兄在左
        //     [2] 兄在右 */


        /* <1>當前節點是根節點 */
        if (null == parNode) {
            return;
        /* <2>兄弟節點是黑色 */
        } else if (TreeColor.BLACK == broNode.treeColor) {
            /* <2.1>兄弟節點的子節點全爲NIL或者全爲黑色 */
            if ((null == broNode.left && null == broNode.right) 
                    || (broNode.left != null && TreeColor.BLACK ==broNode.left.treeColor && broNode.right != null && TreeColor.BLACK ==broNode.right.treeColor)) {
                /* <2.1.1>父節點是紅色節點 */
                if (TreeColor.RED == parNode.treeColor) {
                    /* 交換父親節點與兄弟節點顏色,平衡結束。 */
                    broNode.treeColor = TreeColor.RED;
                    parNode.treeColor = TreeColor.BLACK;
                /* <2.1.2>父節點是黑色節點 */    
                } else {
                    /* 把兄弟節點塗紅 */
                    broNode.treeColor = TreeColor.RED;
                    /* 把父節點做爲平衡節點繼續遞歸處理 */ 
                    BRNode tempParNode = parNode;
                    parNode = parNode.parent;
                    broNode = parNode==tempParNode.left ? tempParNode.right : tempParNode.left;
                    removeFixUp(parNode, broNode);
                }
            /* <2.2>兄弟節點的子節點不全爲黑色節點 */
            } else {
                /* <2.2.1>(1)兄弟節點爲左子節點,兄弟節點的左子節點爲紅色 
                if (broNode == parNode.left && null != broNode.left && TreeColor.RED == broNode.left.treeColor) {
                    /* 以P爲支點右旋;交換P和B顏色,BL塗黑;平衡結束。 */

                    TreeColor curColor = parNode.treeColor;
                    parNode.treeColor = broNode.treeColor;
                    broNode.treeColor = curColor;
                    broNode.left.treeColor = TreeColor.BLACK;
                    rightHand(parNode, broNode);
                /* <2.2.1>(2)兄弟節點爲右子節點,兄弟節點的右子節點爲紅色 */
                } else if(broNode == parNode.right && null != broNode.right && TreeColor.RED == broNode.right.treeColor) {
                    /* 以P爲支點左旋,交換P和B顏色,BR塗黑,平衡結束。 */
                    TreeColor curColor = parNode.treeColor;
                    parNode.treeColor = broNode.treeColor;
                    broNode.treeColor = curColor;
                    broNode.right.treeColor = TreeColor.BLACK;
                    leftHand(parNode, broNode);
                /* <2.2.2>(1)兄弟節點爲左子節點,兄弟節點的左子節點爲黑色 */
                } else if (broNode == parNode.left && null != broNode.left && TreeColor.BLACK == broNode.left.treeColor) {
                    /* 以B爲支點左旋,交換B和BR顏色 */
                    TreeColor broColor = broNode.treeColor;
                    broNode.treeColor = broNode.right.treeColor;
                    broNode.right.treeColor = broColor;
                    leftHand(broNode, broNode.right);

                    /* 轉至2.2.1-(1) */
                    removeFixUp(parNode, broNode.right);
                /* <2.2.2>(2)兄弟節點爲右子節點,兄弟節點的右子節點爲黑色 */        
                } else if (broNode == parNode.right && null != broNode.right && TreeColor.BLACK == broNode.right.treeColor) {
                    /* 以B爲支點右旋,交換B和BL顏色 */
                    TreeColor broColor = broNode.treeColor;
                    broNode.treeColor = broNode.left.treeColor;
                    broNode.left.treeColor = broColor;
                    rightHand(broNode, broNode.left);

                    /* 轉至2.2.1-(2) */
                    removeFixUp(parNode, broNode.left);
                }
            }
        /* <3>兄弟節點爲紅色 */
        } else if (TreeColor.RED == broNode.treeColor) {
            /* <3.1>兄弟節點爲左子節點 */
            if (broNode == parNode.left) {
                /* 以P爲支點右旋,交換P和B顏色,轉向情形<2>兄黑 */
                TreeColor broColor = parNode.treeColor;
                parNode.treeColor = broNode.treeColor;
                broNode.treeColor = broColor;
                rightHand(parNode, broNode);
                removeFixUp(parNode, broNode.right);
            /* <3.2>兄弟節點爲右子節點 */
            } else if (broNode == parNode.right) {
                /* 以P爲支點左旋,交換P和B顏色,轉向情形<2>兄黑 */
                TreeColor broColor = parNode.treeColor;
                parNode.treeColor = broNode.treeColor;
                broNode.treeColor = broColor;
                leftHand(parNode, broNode);
                removeFixUp(parNode, broNode.left);
            }
        }
    }
    /**
     * 左旋
     * @param parent 父節點
     * @param current 中間節點
     */

    private void leftHand(BRNode parent, BRNode current) {
        BRNode grandPa = parent.parent;
        if (grandPa != null) {
            if (grandPa.left == parent) {
                grandPa.left = current;
            } else {
                grandPa.right = current;
            }
        }
        parent.parent = current;
        parent.right = current.left;
        current.left.parent = parent;

        current.parent = grandPa;
        current.left = parent;
    }

    /**
     * 右旋
     * @param parent 父節點
     * @param current 中間節點
     */

    private void rightHand(BRNode parent, BRNode current) {
        BRNode grandPa = parent.parent;
        if (grandPa != null) {
            if (grandPa.left == parent) {
                grandPa.left = current;
            } else {
                grandPa.right = current;
            }
        }
        parent.parent = current;
        parent.left = current.right;
        current.right.parent = parent;

        current.parent = grandPa;
        current.right = parent;
    }

}

圖例還在寫,添加的代碼下次上傳,由於是先學的添加,後學的刪除,如今添加方法已經模糊了。。。ui

相關文章
相關標籤/搜索