1. 程式人生 > >二叉樹與紅黑樹的java實現

二叉樹與紅黑樹的java實現

二叉樹的java實現

public class BinaryTree {

    /**
     * 根節點
     */
    private static Node root;

    static class Node {
        int key;
        Node left, right, parent;

        public Node(int key) {
            this.key = key;
        }
    }

    public BinaryTree(int key) {
        root = new
Node(key); } /** * 中序遍歷 * * @param node 根節點 */ public void inOrderTreeWalk(Node node) { if (node != null) { inOrderTreeWalk(node.left); System.out.print(node.key + ","); inOrderTreeWalk(node.right); } } /** * 查詢 * *
@param node 根節點 * @param key 查詢值 * @return */ public Node treeSearch(Node node, int key) { while (node != null && key != node.key) { if (key < node.key) { node = node.left; } else { node = node.right; } }
return node; } /** * 最小值 * * @param node 根節點 * @return */ public Node treeMinimum(Node node) { while (node.left != null) { node = node.left; } return node; } /** * 最大值 * * @param node 根節點 * @return */ public Node treeMaximum(Node node) { while (node.right != null) { node = node.right; } return node; } /** * 前驅 * * @param node 根節點 * @return */ public Node treePredecessor(Node node) { // 如果存在左子樹,返回左子樹的最大值 if (node.left != null) { return treeMaximum(node.left); } Node y = node.parent; // 當不存在左子樹時,返回最低祖先節點 while (y != null && node == y.left) { node = y; y = y.parent; } return y; } /** * 後繼 * * @param node 根節點 * @return */ public Node treeSuccessor(Node node) { // 如果存在右子樹,返回右子樹的最小值 if (node.right != null) { return treeMinimum(node.right); } Node y = node.parent; // 當不存在右子樹時,返回最低祖先節點 while (y != null && node == y.right) { node = y; y = y.parent; } return y; } /** * 插入 * * @param key 插入節點的關鍵值 */ public void treeInsert(int key) { // 建立插入節點 Node node = new Node(key); // 定義插入節點的父節點變數 Node y = null; // 定義臨時變數存根節點 Node x = root; // 在根節點的左、右子樹中查詢插入位置 while (x != null) { y = x; if (key < x.key) { x = x.left; } else { x = x.right; } } node.parent = y; if (y == null) { root = node; } else if (key < y.key) { y.left = node; } else { y.right = node; } } /** * 刪除 * * @param node 刪除節點 * @return */ public Node treeDelete(Node node) { // 定義臨時變數存刪除節點或後繼節點 Node y; // 當刪除節點至多有一個孩子時 if (node.left == null || node.right == null) { y = node; } else {// 當刪除節點有兩個孩子時,y存後繼節點 y = treeSuccessor(node); } // 定義臨時變數存刪除節點的孩子節點 Node x; if (y.left != null) { x = y.left; } else { x = y.right; } if (x != null) { x.parent = y.parent; } if (y.parent == null) { root = x; } else if (y == y.parent.left) { y.parent.left = x; } else { y.parent.right = x; } // 當y為後繼節點時,將y的關鍵值賦給刪除節點 if (y != node) { node.key = y.key; } return y; } }

紅黑樹的java實現(備註:中序遍歷、查詢、最大、最小、前驅、後繼與二叉樹基本一致)

public class RBTree {

    /**
     * 根節點
     */
    private static Node root;

    /**
     * nil節點是紅黑樹的葉子節點不同於二叉樹的葉子節點
     * 顏色為黑色,key、left、right、parent可以是任意允許的值
     * 這裡key設定為0,left、right、parent為null
     */
    private Node nil = new Node(true);

    static class Node {
        int key;
        Node left, right, parent;
        boolean color;// true黑,false紅

        public Node(int key) {
            this.key = key;
        }

        public Node(boolean color) {
            this.color = color;
        }

        public boolean equals(Node node) {
            return this.key == node.key;
        }
    }

    public RBTree(int key) {
        root = new Node(key);
    }

    /**
     * 中序遍歷
     * 
     * @param node 根節點
     */
    public void inOrderTreeWalk(Node node) {
        if (node != null && !node.equals(nil)) {
            inOrderTreeWalk(node.left);
            System.out.print((node.color == true ? "黑" : "紅") + node.key + ",");
            inOrderTreeWalk(node.right);
        }
    }

    /**
     * 查詢
     * 
     * @param node 根節點
     * @param key 查詢值
     * @return
     */
    public Node treeSearch(Node node, int key) {
        while (node != null && key != node.key) {
            if (key < node.key) {
                node = node.left;
            } else {
                node = node.right;
            }
        }
        return node;
    }

    /**
     * 最小值
     * 
     * @param node 根節點
     * @return
     */
    public Node treeMinimum(Node node) {
        while (node.left != null) {
            node = node.left;
        }
        return node;
    }

    /**
     * 最大值
     * 
     * @param node 根節點
     * @return
     */
    public Node treeMaximum(Node node) {
        while (node.right != null) {
            node = node.right;
        }
        return node;
    }

    /**
     * 前驅
     * 
     * @param node 根節點
     * @return
     */
    public Node treePredecessor(Node node) {
        // 如果存在左子樹,返回左子樹的最大值
        if (node.left != null) {
            return treeMaximum(node.left);
        }
        Node y = node.parent;
        // 當不存在左子樹時,返回最低祖先節點
        while (y != null && node == y.left) {
            node = y;
            y = y.parent;
        }
        return y;
    }

    /**
     * 後繼
     * 
     * @param node 根節點
     * @return
     */
    public Node treeSuccessor(Node node) {
        // 如果存在右子樹,返回右子樹的最小值
        if (node.right != null) {
            return treeMinimum(node.right);
        }
        Node y = node.parent;
        // 當不存在右子樹時,返回最低祖先節點
        while (y != null && node == y.right) {
            node = y;
            y = y.parent;
        }
        return y;
    }

    /**
     * 左旋(node節點必有右孩子)
     * 
     * @param node 
     */
    public void leftTotate(Node node) {
        Node y = node.right;
        node.right = y.left;
        if (y.left != null)
            y.left.parent = node;
        y.parent = node.parent;
        if (node.parent == null) {
            root = y;
        } else if (node == node.parent.left) {
            node.parent.left = y;
        } else {
            node.parent.right = y;
        }
        node.parent = y;
        y.left = node;
    }

    /**
     * 右旋(node節點必有左孩子)
     * 
     * @param node
     */
    public void rightTotate(Node node) {
        Node y = node.left;
        node.left = y.right;
        if (y.right != null)
            y.right.parent = node;
        y.parent = node.parent;
        if (node.parent == null) {
            root = y;
        } else if (node == node.parent.left) {
            node.parent.left = y;
        } else {
            node.parent.right = y;
        }
        node.parent = y;
        y.right = node;
    }

    /**
     * 插入
     * 
     * @param key 插入節點的關鍵值
     */
    public void RBTreeInsert(int key) {
        // 建立插入節點
        Node node = new Node(key);
        // 定義插入節點的父節點變數
        Node y = null;
        // 定義臨時變數存根節點
        Node x = root;
        // 在根節點的左、右子樹中查詢插入位置
        while (x != null) {
            y = x;
            if (key < x.key) {
                x = x.left;
            } else {
                x = x.right;
            }
        }
        node.parent = y;
        if (y == null) {
            root = node;
        } else if (key < y.key) {
            y.left = node;
        } else {
            y.right = node;
        }
        RBTreeInsertFixup(node);
    }

    /**
     * 插入後修復
     * 
     * @param node 插入節點
     */
    public void RBTreeInsertFixup(Node node) {
        // 當插入節點的父節點為紅色時,執行迴圈
        while (node.parent != null && !node.parent.color && node.parent.parent != null) {
            // 當插入節點的父節點為其爺爺節點的左孩子時
            if (node.parent == node.parent.parent.left) {
                // 定義y存叔叔節點
                Node y = node.parent.parent.right;
                // 如果叔叔節點為紅色,將父節點與叔叔節點變成黑色,爺爺節點變成紅色,將插入節點升級為爺爺節點
                if (y != null && !y.color) {
                    node.parent.color = true;
                    y.color = true;
                    node.parent.parent.color = false;
                    node = node.parent.parent;
                } else if (node == node.parent.right) {//如果叔叔節點為黑色,插入節點是父節點的右孩子,將插入節點升級為父節點,左旋插入節點
                    node = node.parent;
                    leftTotate(node);
                } else {//如果叔叔節點為黑色,插入節點是父節點的左孩子,將父節點變成黑色,爺爺節點變成紅色,右旋爺爺節點
                    node.parent.color = true;
                    node.parent.parent.color = false;
                    rightTotate(node.parent.parent);
                }
            } else {// 當插入節點的父節點為其爺爺節點的右孩子時
                // 定義y存叔叔節點
                Node y = node.parent.parent.left;
                // 如果叔叔節點為紅色,將父節點與叔叔節點變成黑色,爺爺節點變成紅色,將插入節點升級為爺爺節點
                if (y != null && !y.color) {
                    node.parent.color = true;
                    y.color = true;
                    node.parent.parent.color = false;
                    node = node.parent.parent;
                } else if (node == node.parent.left) {//如果叔叔節點為黑色,插入節點是父節點的左孩子,將插入節點升級為父節點,右旋插入節點
                    node = node.parent;
                    rightTotate(node);
                } else {//如果叔叔節點為黑色,插入節點是父節點的右孩子,將父節點變成黑色,爺爺節點變成紅色,左旋爺爺節點
                    node.parent.color = true;
                    node.parent.parent.color = false;
                    leftTotate(node.parent.parent);
                }
            }
        }
        // 將根節點變成黑色
        if (root.parent != null) {
            root = root.parent;
        }
        root.color = true;
    }

    /**
     * 刪除
     * 
     * @param node 刪除節點
     * @return
     */
    public Node RBTreeDelete(Node node) {
        // 定義臨時變數存刪除節點或後繼節點
        Node y;
        // 當刪除節點至多有一個孩子時
        if (node.left == null || node.right == null) {
            y = node;
        } else {// 當刪除節點有兩個孩子時,y存後繼節點
            y = treeSuccessor(node);
        }
        // 定義臨時變數存刪除節點的孩子節點
        Node x;
        if (y.left != null) {
            x = y.left;
        } else {
            x = y.right;
        }
        if (x != null) {
            x.parent = y.parent;
        } else {
            x = nil;
            x.parent = y.parent;
        }
        if (y.parent == null) {
            root = x;
        } else if (y == y.parent.left) {
            y.parent.left = x;
        } else {
            y.parent.right = x;
        }
        // 當y為後繼節點時,將y的關鍵值賦給刪除節點
        if (y != node) {
            node.key = y.key;
        }
        // 當y為黑色時,需要修復紅黑樹
        if (y.color) {
            RBTreeDeleteFixup(x);
        }
        return y;
    }

    /**
     * 刪除後修復
     * 
     * @param node 刪除節點的孩子節點
     */
    public void RBTreeDeleteFixup(Node node) {
        // 當node不等於根節點並且為黑色時,執行迴圈
        while (node != root && (node == nil || node.color)) {
            // 如果node節點為父節點的左孩子
            if (node == node.parent.left) {
                // 定義w存兄弟節點
                Node w = node.parent.right;
                // 當兄弟節點為紅色時,將兄弟節點變成黑色,父節點變成紅色,左旋父節點,更新兄弟節點
                if (!w.color) {
                    w.color = true;
                    node.parent.color = false;
                    leftTotate(node.parent);
                    w = node.parent.right;
                } else if (w.left.color && w.right.color) {//當兄弟節點為黑色且其兩個孩子都為黑色時,將兄弟節點變成紅色,將node節點升級為父節點
                    w.color = false;
                    node = node.parent;
                } else if (w.right.color) {//當兄弟節點為黑色且其左孩子為紅色、其右孩子為黑色時,將其左孩子變成黑色、兄弟節點變成紅色,右旋兄弟節點,更新兄弟節點
                    w.left.color = true;
                    w.color = false;
                    rightTotate(w);
                    w = node.parent.right;
                } else {//當兄弟節點為黑色且其右孩子為紅色時,將父節點的顏色賦給兄弟節點,父節點變成黑色,兄弟節點的右孩子變成黑色,左旋父節點
                    w.color = node.parent.color;
                    node.parent.color = true;
                    w.right.color = true;
                    leftTotate(node.parent);
                    // 將根節點賦給node
                    if (root.parent != null) {
                        root = root.parent;
                    }
                    node = root;
                }
            } else {// 如果node節點為父節點的右孩子
                // 定義w存兄弟節點
                Node w = node.parent.left;
                // 當兄弟節點為紅色時,將兄弟節點變成黑色,父節點變成紅色,右旋父節點,更新兄弟節點
                if (!w.color) {
                    w.color = true;
                    node.parent.color = false;
                    rightTotate(node.parent);
                    w = node.parent.left;
                } else if (w.left.color && w.right.color) {//當兄弟節點為黑色且其兩個孩子都為黑色時,將兄弟節點變成紅色,將node節點升級為父節點
                    w.color = false;
                    node = node.parent;
                } else if (w.left.color) {//當兄弟節點為黑色且其左孩子為黑色、其右孩子為紅色時,將其右孩子變成黑色、兄弟節點變成紅色,左旋兄弟節點,更新兄弟節點
                    w.right.color = true;
                    w.color = false;
                    leftTotate(w);
                    w = node.parent.left;
                } else {//當兄弟節點為黑色且其左孩子為紅色時,將父節點的顏色賦給兄弟節點,父節點變成黑色,兄弟節點的左孩子變成黑色,右旋父節點
                    w.color = node.parent.color;
                    node.parent.color = true;
                    w.left.color = true;
                    rightTotate(node.parent);
                    // 將根節點賦給node
                    if (root.parent != null) {
                        root = root.parent;
                    }
                    node = root;
                }
            }
        }
        // 將node節點變成黑色
        node.color = true;
    }

    public static void main(String[] args) {
        int[] arr = { 21, 3, 6, 7, 12, 25, 17, 8, 15 };
        RBTree rb = new RBTree(21);
        for (int i = 1; i < arr.length; i++) {
            rb.RBTreeInsert(arr[i]);
        }
        rb.inOrderTreeWalk(root);
        rb.RBTreeDelete(rb.treeSearch(root, 21));
        System.out.println();
        rb.inOrderTreeWalk(root);
    }

}