JAVA中紅黑樹的實現

平衡二叉樹是強平衡,紅黑樹是弱平衡(黑節點平衡),所以平衡二叉樹調整結構時花費的操作更多,適合於讀操作頻繁的情況,紅黑樹適合與寫操作平衡的情況。

​
package RBTree;

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

    private RBTNode<T> mRoot;    // 根結點

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

    public class RBTNode<T extends Comparable<T>> {
        boolean color;        // 顏色
        T key;                // 關鍵字(鍵值)
        RBTNode<T> left;    // 左孩子
        RBTNode<T> right;    // 右孩子
        RBTNode<T> parent;    // 父結點

        public RBTNode(T key, boolean color, RBTNode<T> parent, RBTNode<T> left, RBTNode<T> right) {
            this.key = key;
            this.color = color;
            this.parent = parent;
            this.left = left;
            this.right = right;
        }


        public T getKey() {
            return key;
        }

        public String toString() {
            return "" + key + (this.color == RED ? "(R)" : "B");
        }
    }

    public RBTree() {
        mRoot = null;
    }

    private RBTNode<T> parentOf(RBTNode<T> node) {
        return node != null ? node.parent : null;
    }

    private boolean colorOf(RBTNode<T> node) {
        return node != null ? node.color : BLACK;
    }

    private boolean isRed(RBTNode<T> node) {
        return ((node != null) && (node.color == RED)) ? true : false;
    }

    private boolean isBlack(RBTNode<T> node) {
        return !isRed(node);
    }

    private void setBlack(RBTNode<T> node) {
        if (node != null)
            node.color = BLACK;
    }

    private void setRed(RBTNode<T> node) {
        if (node != null)
            node.color = RED;
    }

    private void setParent(RBTNode<T> node, RBTNode<T> parent) {
        if (node != null)
            node.parent = parent;
    }

    private void setColor(RBTNode<T> node, boolean color) {
        if (node != null)
            node.color = color;
    }

    /*
     * 前序遍歷"紅黑樹"
     */
    private void preOrder(RBTNode<T> tree) {
        if (tree != null) {
            System.out.print(tree.key + " ");
            preOrder(tree.left);
            preOrder(tree.right);
        }
    }

    public void preOrder() {
        preOrder(mRoot);
    }

    /*
     * 中序遍歷"紅黑樹"
     */
    private void inOrder(RBTNode<T> tree) {
        if (tree != null) {
            inOrder(tree.left);
            System.out.print(tree.key + " ");
            inOrder(tree.right);
        }
    }

    public void inOrder() {
        inOrder(mRoot);
    }


    /*
     * 後序遍歷"紅黑樹"
     */
    private void postOrder(RBTNode<T> tree) {
        if (tree != null) {
            postOrder(tree.left);
            postOrder(tree.right);
            System.out.print(tree.key + " ");
        }
    }

    public void postOrder() {
        postOrder(mRoot);
    }


    /*
     * (遞歸實現)查找"紅黑樹x"中鍵值爲key的節點
     */
    private RBTNode<T> search(RBTNode<T> x, T key) {
        if (x == null)
            return x;

        int cmp = key.compareTo(x.key);
        if (cmp < 0)
            return search(x.left, key);
        else if (cmp > 0)
            return search(x.right, key);
        else
            return x;
    }

    public RBTNode<T> search(T key) {
        return search(mRoot, key);
    }

    /*
     * (非遞歸實現)查找"紅黑樹x"中鍵值爲key的節點
     */
    private RBTNode<T> iterativeSearch(RBTNode<T> x, T key) {
        while (x != null) {
            int cmp = key.compareTo(x.key);

            if (cmp < 0)
                x = x.left;
            else if (cmp > 0)
                x = x.right;
            else
                return x;
        }

        return x;
    }

    public RBTNode<T> iterativeSearch(T key) {
        return iterativeSearch(mRoot, key);
    }

    /*
     * 查找最小結點:返回tree爲根結點的紅黑樹的最小結點。
     */
    private RBTNode<T> minimum(RBTNode<T> tree) {
        if (tree == null)
            return null;

        while (tree.left != null)
            tree = tree.left;
        return tree;
    }

    public T minimum() {
        RBTNode<T> p = minimum(mRoot);
        if (p != null)
            return p.key;

        return null;
    }

    /*
     * 查找最大結點:返回tree爲根結點的紅黑樹的最大結點。
     */
    private RBTNode<T> maximum(RBTNode<T> tree) {
        if (tree == null)
            return null;

        while (tree.right != null)
            tree = tree.right;
        return tree;
    }

    public T maximum() {
        RBTNode<T> p = maximum(mRoot);
        if (p != null)
            return p.key;

        return null;
    }

    /*
     * 找結點(x)的後繼結點。即,查找"紅黑樹中數據值大於該結點"的"最小結點"。
     */
    public RBTNode<T> successor(RBTNode<T> x) {
        // 如果x存在右孩子,則"x的後繼結點"爲 "以其右孩子爲根的子樹的最小結點"。
        if (x.right != null)
            return minimum(x.right);

        // 如果x沒有右孩子。則x有以下兩種可能:
        // (01) x是"一個左孩子",則"x的後繼結點"爲 "它的父結點"。
        // (02) x是"一個右孩子",則查找"x的最低的父結點,並且該父結點要具有左孩子",找到的這個"最低的父結點"就是"x的後繼結點"。
        RBTNode<T> y = x.parent;
        while ((y != null) && (x == y.right)) {
            x = y;
            y = y.parent;
        }

        return y;
    }

    /*
     * 找結點(x)的前驅結點。即,查找"紅黑樹中數據值小於該結點"的"最大結點"。
     */
    public RBTNode<T> predecessor(RBTNode<T> x) {
        // 如果x存在左孩子,則"x的前驅結點"爲 "以其左孩子爲根的子樹的最大結點"。
        if (x.left != null)
            return maximum(x.left);

        // 如果x沒有左孩子。則x有以下兩種可能:
        // (01) x是"一個右孩子",則"x的前驅結點"爲 "它的父結點"。
        // (01) x是"一個左孩子",則查找"x的最低的父結點,並且該父結點要具有右孩子",找到的這個"最低的父結點"就是"x的前驅結點"。
        RBTNode<T> y = x.parent;
        while ((y != null) && (x == y.left)) {
            x = y;
            y = y.parent;
        }

        return y;
    }

    /*
     * 對紅黑樹的節點(x)進行左旋轉
     *
     * 左旋示意圖(對節點x進行左旋):
     *      px                              px
     *     /                               /
     *    x                               y
     *   /  \      --(左旋)-.           / \                #
     *  lx   y                         x  ry
     *     /   \                      /    \
     *    ly   ry                    lx     ly
     *
     *
     */
    private void leftRotate(RBTNode<T> x) {
        // 設置x的右孩子爲y
        RBTNode<T> y = x.right;
        // 將 “y的左孩子” 設爲 “x的右孩子”;
        // 如果y的左孩子非空,將 “x” 設爲 “y的左孩子的父親”
        x.right = y.left;
        if (y.left != null)
            y.left.parent = x;
        // 將 “x的父親” 設爲 “y的父親”
        y.parent = x.parent;
        if (x.parent == null) {
            this.mRoot = y;            // 如果 “x的父親” 是空節點,則將y設爲根節點
        } else {
            if (x.parent.left == x)
                x.parent.left = y;    // 如果 x是它父節點的左孩子,則將y設爲“x的父節點的左孩子”
            else
                x.parent.right = y;    // 如果 x是它父節點的左孩子,則將y設爲“x的父節點的左孩子”
        }
        // 將 “x” 設爲 “y的左孩子”
        y.left = x;
        // 將 “x的父節點” 設爲 “y”
        x.parent = y;
    }

    /*
     * 對紅黑樹的節點(y)進行右旋轉
     *
     * 右旋示意圖(對節點y進行左旋):
     *            py                               py
     *           /                                /
     *          y                                x
     *         /  \      --(右旋)-.            /  \                     #
     *        x   ry                           lx   y
     *       / \                                   / \                   #
     *      lx  rx                                rx  ry
     *
     */
    private void rightRotate(RBTNode<T> y) {
        // 設置x是當前節點的左孩子。
        RBTNode<T> x = y.left;

        // 將 “x的右孩子” 設爲 “y的左孩子”;
        // 如果"x的右孩子"不爲空的話,將 “y” 設爲 “x的右孩子的父親”
        y.left = x.right;
        if (x.right != null)
            x.right.parent = y;

        // 將 “y的父親” 設爲 “x的父親”
        x.parent = y.parent;

        if (y.parent == null) {
            this.mRoot = x;            // 如果 “y的父親” 是空節點,則將x設爲根節點
        } else {
            if (y == y.parent.right)
                y.parent.right = x;    // 如果 y是它父節點的右孩子,則將x設爲“y的父節點的右孩子”
            else
                y.parent.left = x;    // (y是它父節點的左孩子) 將x設爲“x的父節點的左孩子”
        }

        // 將 “y” 設爲 “x的右孩子”
        x.right = y;

        // 將 “y的父節點” 設爲 “x”
        y.parent = x;
    }

    /*
     * 紅黑樹插入修正函數
     *
     * 在向紅黑樹中插入節點之後(失去平衡),再調用該函數;
     * 目的是將它重新塑造成一顆紅黑樹。
     *
     * 參數說明:
     *     node 插入的結點        // 對應《算法導論》中的z
     */
    private void insertFixUp(RBTNode<T> node) {
        RBTNode<T> parent, gparent;
        // 若“父節點存在,並且父節點的顏色是紅色”
        while (((parent = parentOf(node)) != null) && isRed(parent)) {
            gparent = parentOf(parent);
            //若“父節點”是“祖父節點的左孩子”
            if (parent == gparent.left) {
                // Case 1條件:叔叔節點是紅色
                RBTNode<T> uncle = gparent.right;
                if ((uncle != null) && isRed(uncle)) {
                    setBlack(uncle);
                    setBlack(parent);
                    setRed(gparent);
                    node = gparent;
                    continue;
                }
                // Case 2條件:叔叔是黑色,且當前節點是右孩子
                if (parent.right == node) {
                    RBTNode<T> tmp;
                    leftRotate(parent);
                    tmp = parent;
                    parent = node;
                    node = tmp;
                }
                // Case 3條件:叔叔是黑色,且當前節點是左孩子。
                setBlack(parent);
                setRed(gparent);
                rightRotate(gparent);
            } else {    //若“z的父節點”是“z的祖父節點的右孩子”
                // Case 1條件:叔叔節點是紅色
                RBTNode<T> uncle = gparent.left;
                if ((uncle != null) && isRed(uncle)) {
                    setBlack(uncle);
                    setBlack(parent);
                    setRed(gparent);
                    node = gparent;
                    continue;
                }
                // Case 2條件:叔叔是黑色,且當前節點是左孩子
                if (parent.left == node) {
                    RBTNode<T> tmp;
                    rightRotate(parent);
                    tmp = parent;
                    parent = node;
                    node = tmp;
                }
                // Case 3條件:叔叔是黑色,且當前節點是右孩子。
                setBlack(parent);
                setRed(gparent);
                leftRotate(gparent);
            }
        }
        // 將根節點設爲黑色
        setBlack(this.mRoot);
    }

    /*
     * 將結點插入到紅黑樹中
     *
     * 參數說明:
     *     node 插入的結點        // 對應《算法導論》中的node
     */
    private void insert(RBTNode<T> node) {
        int cmp;
        RBTNode<T> y = null;
        RBTNode<T> x = this.mRoot;
        // 1. 將紅黑樹當作一顆二叉查找樹,將節點添加到二叉查找樹中。
        while (x != null) {
            y = x;
            cmp = node.key.compareTo(x.key);
            if (cmp < 0)
                x = x.left;
            else
                x = x.right;
        }
        node.parent = y;
        if (y != null) {
            cmp = node.key.compareTo(y.key);
            if (cmp < 0)
                y.left = node;
            else
                y.right = node;
        } else {
            this.mRoot = node;
        }
        // 2. 設置節點的顏色爲紅色
        node.color = RED;
        // 3. 將它重新修正爲一顆二叉查找樹
        insertFixUp(node);
    }

    /*
     * 新建結點(key),並將其插入到紅黑樹中
     *
     * 參數說明:
     *     key 插入結點的鍵值
     */
    public void insert(T key) {
        RBTNode<T> node = new RBTNode<T>(key, BLACK, null, null, null);
        // 如果新建結點失敗,則返回。
        if (node != null)
            insert(node);
    }


    /*
     * 紅黑樹刪除修正函數
     *
     * 在從紅黑樹中刪除插入節點之後(紅黑樹失去平衡),再調用該函數;
     * 目的是將它重新塑造成一顆紅黑樹。
     *
     * 參數說明:
     *     node 待修正的節點
     */
    private void removeFixUp(RBTNode<T> node, RBTNode<T> parent) {
        RBTNode<T> other;

        while ((node == null || isBlack(node)) && (node != this.mRoot)) {
            if (parent.left == node) {
                other = parent.right;
                if (isRed(other)) {
                    // Case 1: x的兄弟w是紅色的
                    setBlack(other);
                    setRed(parent);
                    leftRotate(parent);
                    other = parent.right;
                }

                if ((other.left == null || isBlack(other.left)) &&
                        (other.right == null || isBlack(other.right))) {
                    // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的
                    setRed(other);
                    node = parent;
                    parent = parentOf(node);
                } else {

                    if (other.right == null || isBlack(other.right)) {
                        // Case 3: x的兄弟w是黑色的,並且w的左孩子是紅色,右孩子爲黑色。
                        setBlack(other.left);
                        setRed(other);
                        rightRotate(other);
                        other = parent.right;
                    }
                    // Case 4: x的兄弟w是黑色的;並且w的右孩子是紅色的,左孩子任意顏色。
                    setColor(other, colorOf(parent));
                    setBlack(parent);
                    setBlack(other.right);
                    leftRotate(parent);
                    node = this.mRoot;
                    break;
                }
            } else {

                other = parent.left;
                if (isRed(other)) {
                    // Case 1: x的兄弟w是紅色的
                    setBlack(other);
                    setRed(parent);
                    rightRotate(parent);
                    other = parent.left;
                }

                if ((other.left == null || isBlack(other.left)) &&
                        (other.right == null || isBlack(other.right))) {
                    // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的
                    setRed(other);
                    node = parent;
                    parent = parentOf(node);
                } else {

                    if (other.left == null || isBlack(other.left)) {
                        // Case 3: x的兄弟w是黑色的,並且w的左孩子是紅色,右孩子爲黑色。
                        setBlack(other.right);
                        setRed(other);
                        leftRotate(other);
                        other = parent.left;
                    }

                    // Case 4: x的兄弟w是黑色的;並且w的右孩子是紅色的,左孩子任意顏色。
                    setColor(other, colorOf(parent));
                    setBlack(parent);
                    setBlack(other.left);
                    rightRotate(parent);
                    node = this.mRoot;
                    break;
                }
            }
        }

        if (node != null)
            setBlack(node);
    }

    /*
     * 刪除結點(node),並返回被刪除的結點
     *
     * 參數說明:
     *     node 刪除的結點
     */
    private void remove(RBTNode<T> node) {
        RBTNode<T> child, parent;
        boolean color;

        // 被刪除節點的"左右孩子都不爲空"的情況。
        if ((node.left != null) && (node.right != null)) {
            // 被刪節點的後繼節點。(稱爲"取代節點")
            // 用它來取代"被刪節點"的位置,然後再將"被刪節點"去掉。
            RBTNode<T> replace = node;

            // 獲取後繼節點
            replace = replace.right;
            while (replace.left != null)
                replace = replace.left;

            // "node節點"不是根節點(只有根節點不存在父節點)
            if (parentOf(node) != null) {
                if (parentOf(node).left == node)
                    parentOf(node).left = replace;
                else
                    parentOf(node).right = replace;
            } else {
                // "node節點"是根節點,更新根節點。
                this.mRoot = replace;
            }

            // child是"取代節點"的右孩子,也是需要"調整的節點"。
            // "取代節點"肯定不存在左孩子!因爲它是一個後繼節點。
            child = replace.right;
            parent = parentOf(replace);
            // 保存"取代節點"的顏色
            color = colorOf(replace);

            // "被刪除節點"是"它的後繼節點的父節點"
            if (parent == node) {
                parent = replace;
            } else {
                // child不爲空
                if (child != null)
                    setParent(child, parent);
                parent.left = child;

                replace.right = node.right;
                setParent(node.right, replace);
            }

            replace.parent = node.parent;
            replace.color = node.color;
            replace.left = node.left;
            node.left.parent = replace;

            if (color == BLACK)
                removeFixUp(child, parent);

            node = null;
            return;
        }

        if (node.left != null) {
            child = node.left;
        } else {
            child = node.right;
        }

        parent = node.parent;
        // 保存"取代節點"的顏色
        color = node.color;

        if (child != null)
            child.parent = parent;

        // "node節點"不是根節點
        if (parent != null) {
            if (parent.left == node)
                parent.left = child;
            else
                parent.right = child;
        } else {
            this.mRoot = child;
        }

        if (color == BLACK)
            removeFixUp(child, parent);
        node = null;
    }

    /*
     * 刪除結點(z),並返回被刪除的結點
     *
     * 參數說明:
     *     tree 紅黑樹的根結點
     *     z 刪除的結點
     */
    public void remove(T key) {
        RBTNode<T> node;
        if ((node = search(mRoot, key)) != null)
            remove(node);
    }

    /*
     * 銷燬紅黑樹
     */
    private void destroy(RBTNode<T> tree) {
        if (tree == null)
            return;

        if (tree.left != null)
            destroy(tree.left);
        if (tree.right != null)
            destroy(tree.right);

        tree = null;
    }

    public void clear() {
        destroy(mRoot);
        mRoot = null;
    }

    /*
     * 打印"紅黑樹"
     *
     * key        -- 節點的鍵值
     * direction  --  0,表示該節點是根節點;
     *               -1,表示該節點是它的父結點的左孩子;
     *                1,表示該節點是它的父結點的右孩子。
     */
    private void print(RBTNode<T> tree, T key, int direction) {

        if (tree != null) {

            if (direction == 0)    // tree是根節點
                System.out.printf("%2d(B) is root\n", tree.key);
            else                // tree是分支節點
                System.out.printf("%2d(%s) is %2d's %6s child\n", tree.key, isRed(tree) ? "R" : "B", key, direction == 1 ? "right" : "left");

            print(tree.left, tree.key, -1);
            print(tree.right, tree.key, 1);
        }
    }

    public void print() {
        if (mRoot != null)
            print(mRoot, mRoot.key, 0);
    }
}


​

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章