紅黑書——算法導論

一顆二叉查找樹若是知足下面的紅黑性質,則爲一棵紅黑樹:html

(1) 每一個節點或者是黑色,或者是紅色。
(2) 根節點是黑色。
(3) 每一個葉子節點是黑色。 【注意:這裏葉子節點,是指爲空的葉子節點】
(4) 若是一個節點是紅色的,則它的子節點必須是黑色的。     《等價於》 若是一個節點是紅色的,則它的父節點必須是黑色節點;
(5) 從一個節點到該節點的子孫節點的全部路徑上包含相同數目的黑節點。java

首先定義一棵紅黑樹(java)node

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;
        }

    }

    ...
}

向一棵紅黑樹中插入一個新結點可在O(lg n)時間內完成,可是此操做可能會破壞紅黑樹的性質。因此可使用TREE-INSERT過程,來將節點z插入樹T內。過程能夠分爲兩步:算法

1)將T做爲一棵普通的二叉查找樹將結點z插入樹T內,而後將z着爲紅色函數

2)步驟1)可能會破壞紅黑樹的性質4),因此使用一個輔助程序RB-INSERT-FIXUP來對結點從新着色並旋轉,使得新着色的書知足紅黑性質。this

RB-INSERT-FIXUP根據三種狀況來對新造成的樹進行調整:spa

 

如下操做涉及到樹的左旋和右旋操做,具體步驟能夠參考下面的一篇引用blog,同時代碼也是從這篇blog裏面貼過來的。指針

case1: z的叔叔y是紅色的(新插入的節點z已經着色爲紅色) code

此調整過程在樹中無論循環,指針z在樹中上移兩層htm

case 2:z的叔叔y是黑色的,並且z是右孩子


此時能夠經過左旋來轉變這種狀況爲case 3,如圖所示

case 3 z的叔叔y是黑色的,並且z是左孩子  


此操做經過一次右旋來完成

 

下面給出插入算法java實現:

/* 
 * 將結點插入到紅黑樹中
 *
 * 參數說明:
 *     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 插入的結點        // 對應《算法導論》中的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);
}

 

 referance:

http://www.cnblogs.com/skywang12345/p/3624343.html

《算法導論》

相關文章
相關標籤/搜索