【算法導論】第十三章,紅黑樹。java

1、結點java

package com.company.RedBlackTree;

/**
 * Created by jiayi on 2016/10/29.
 */

enum colors{
    red,black;
};
public class RedBlackTreeNode implements Cloneable {
    colors color;
    int key;
    RedBlackTreeNode left;
    RedBlackTreeNode right;
    RedBlackTreeNode p;
    int depth;
    public RedBlackTreeNode clone() throws CloneNotSupportedException{ //淺拷貝
        RedBlackTreeNode cloned = (RedBlackTreeNode) super.clone();
        return cloned;
    }
    RedBlackTreeNode(){
        color = colors.black;
        key = 0;
        left = null;
        right = null;
        p = null;
        depth = 0;
    }
    RedBlackTreeNode(int key){
        color = colors.black;
        this.key = key;
        left = null;
        right = null;
        p = null;
        depth = 0;
    }

    public boolean equals(RedBlackTreeNode x){
        if(x.key == key && x.color == color && x.left == left && x.right == right){
            return true;
        }else {
            return false;
        }
    }

}

2、紅黑樹的插入(RBInsert)、刪除(RBDelete)、鏈接(RBJoin)node

package com.company.RedBlackTree;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Map;
import java.util.HashMap;

/**
 * Created by jiayi on 2016/10/29.
 */
public class RedBlackTree implements Cloneable{
public RedBlackTreeNode nil;
public RedBlackTreeNode root;
public int N;
public RedBlackTree(){
    nil = new RedBlackTreeNode();
    root = nil;
}
public RedBlackTree(RedBlackTreeNode root){
    this.root = root;
    nil = new RedBlackTreeNode();

}
public void test(int[] a){
    for( int i = 0 ; i < a.length ; i++ ){
        RedBlackTreeNode temp = new RedBlackTreeNode(a[i]);
        RBInsert(temp);
        bfsTree();
        //Print();
    }
    /*bfsTree();
    RedBlackTreeNode temp = RBSearch(root,a[5]);
    RBDelete(temp);
    bfsTree();*/

//Print();
}

  
// 計算某節點在整棵樹的第幾層(ROOT爲第1層)
public int getLevelOfFullTree(RedBlackTreeNode node) {
int depth = 0;
RedBlackTreeNode t = node;
      while (t != nil) {
            depth++;
            t = t.p;
            }
        return depth;
    }
    // 樹形本層節點打印
private void printTreeLevel(String[] nodes)    {
    System.out.print("\n|");
    for (int j = 0; j < nodes.length; j++) {
    if (nodes[j] == null||nodes[j].length() == 0) {
        // 打印兩位數字的佔位符
        System.out.printf("---");
    } else {
        // 打印節點
        System.out.printf("%3s", nodes[j]);
        // 重置數組
        nodes[j] = "";
    }
}
System.out.print("|");

}算法

public void bfsTree() {
        System.out.print("\n------------------ 樹形打印開始 ------------------");

        if (this.root.equals( nil)) {
            System.out.print("\n樹爲pw");
            return;
        }

        // 二叉樹的高度
        int maxLevel = getDepth(root);
        // 滿二叉樹時的總結點數
        int fullTotal = (int) Math.pow(2, maxLevel) - 1;
        // 水平數組
        //int[] nodes = new int[fullTotal];
        String[] nodes = new String[fullTotal];

        // 上一個節點的層次
        int prevLevel = 1;
        // 每層的起始下標
        int start = 0;
        // 每一層的元素的間距
        int stepSize = 0;

        // 廣度優先遍歷
        Queue<RedBlackTreeNode> queue = new LinkedList<>();
        queue.offer(root);
        RedBlackTreeNode node = nil;
        // 若是用數組存儲二叉樹,indexMap中存儲各節點對應數組的下標
        Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
        while (!queue.isEmpty()) {
            // 刪除隊列頭結點
            node = queue.poll();
            // 某節點在整棵樹的第幾層(ROOT爲第1層)
            int levelOfFullTree = getLevelOfFullTree(node);

            // 若是當前深度比前一個節點的嘗試大,則開始的新一層的節點訪問
            if (levelOfFullTree > prevLevel) {
                // 打印層次的節點
                printTreeLevel(nodes);
            }

            // 計算新的層次的開始下標與步長
            start = (int) Math.pow(2, maxLevel - levelOfFullTree) - 1;
            stepSize = (int) Math.pow(2, maxLevel - levelOfFullTree + 1);
            // System.out.print("\n" + "start:" + start + ",stepSize:" + stepSize);

            // 記錄節點的下標
            int idx = -1;
            if (node == root) {
                indexMap.put(node.key, 1);
                idx = 1;
            } else{
                if (node == node.p.left) {
                    idx = 2 * indexMap.get(node.p.key) - 1;
                } else if (node == node.p.right) {
                    idx = 2 * indexMap.get(node.p.key);
                }
                indexMap.put(node.key, idx);
            }

            // 計算映射到水平數組的位置
            int y = start + (idx - 1) * stepSize;
            String c;
            if(node.color == colors.black){
                c = "b";
            }else {
                c = "r";
            }
            nodes[y] = String.valueOf(node.key) + c ;
            // System.out.print("\n" + "node.value:" + node.value + ",y:" + y);

            // 將節點的左孩子加入隊列
            if (!node.left.equals( nil)) {
                queue.offer(node.left);
            }
            // 將節點的右孩子加入隊列
            if (!node.right.equals( nil)) {
                queue.offer(node.right);
            }

            // 保留層次數,爲下次循環使用
            prevLevel = levelOfFullTree;
        }

        // 打印最底層的節點,由於while的推出,最底層次的節點沒有打印,在這裏單獨打印
        this.printTreeLevel(nodes);
        System.out.print("\n------------------ 樹形打印結束 ------------------");
    }

    // 計算以某節點爲根的樹的深度(從1開始)
    public int getDepth(RedBlackTreeNode node) {
        if (node.equals( nil)) {
            return 0;
        }

        return 1 + Math.max(this.getDepth(node.left), this.getDepth(node.right));
    }
    /**
     * 二叉樹的廣度優先遍歷,按照樹形打印此樹
     *
 *
 * 算法用到的參數:
 * 1:二叉樹的最大深度。
 * 2:每一個節點在二叉樹中的層次Level,從1開始。
 * 3:每一個節點在該層中的序號indexOfLevel,從1開始。
 * 注:
 *  (1)Level和indexOfLevel能夠在廣度優先遍歷時用計數器實現。
 *  (2)Level和indexOfLevel也能夠在向樹中插入新節點時,初始化到節點中。
 *      若是用數組存儲二叉樹,假設父節點下標爲i,則其左孩子的下標是2*i-1,右孩子的下標是2*i+1。
 *
 * 算法基本思路:
 * (1):建立一個水平數組,水平數組的長度爲 "滿二叉樹" 中的節點總數,將二叉樹的全部節點,按滿二叉樹的樣子,投影到水平數組上,每一個節點在水平數組中都對就一個位置。
 * (2):咱們總結一下,對於每個層級,映射到水平數組後,第一個節點的開始下標=s,本層任意相鄰節點的步長(間距)=d,若是下所示
 * 層級   起始下標        步長
 * 1    2^3-1=7     2^4=16
 * 2    2^2-1=3     2^3=8
 * 3    2^1-1=1     2^2=4
 * 4    2^0-1=0     2^1=2
 * (3):有了以上數據,咱們能夠計算出,任意一層,任意一節點在水平數組中的下標,
 * 下標=起始下標+(該節點所在層次-1)*步長
 * (4):OK,每一次每一個節點的位置肯定了,樹形圖天然也肯定了。
 *
 * 另:
 * 若是想要讓輸出特別規矩,咱們必須:
 * 1:先肯定每一個節點的值(即輸出的內容)最多佔多少個字符寬度,假設爲flength。
 *     在輸出樹的過程當中,不論遇到空值仍是有值,都格式化輸出,長度不足flength的,用空格補齊。
 * 2:能夠適當的將水平數組擴大一倍,這樣每層中的各節點之間的距離拉長了,最終看到的結果是整個樹水平放大了。
 *
 */

private RedBlackTreeNode RBSearch(RedBlackTreeNode x, int k){
    while (x != nil){
        if(x.key > k){
            return RBSearch(x.left,k);
        }else if(x.key < k){
            return RBSearch(x.right,k);
        }
        else return x;
    }
    return nil;
}
private void LeftRotate(RedBlackTreeNode x){ // 假設x.right != Nil
    RedBlackTreeNode y = x.right;
    //將y設爲新的子樹根節點
    x.right = y.left;
    if(y.left != nil){
        y.left.p = x;
    }
    if(x.p.right == x){
        x.p.right = y;
        y.p = x.p;
    }else if(x.p.left == x){
        x.p.left = y;
        y.p = x.p;
    }else{
        y.p = nil;
        root = y;
    }
    //x成爲y的左孩子
    y.left = x;
    x.p = y;
    //y的左孩子成爲x的右孩子
}
private void RightRotate(RedBlackTreeNode y){
    //使x成爲新的根節點
    RedBlackTreeNode x = y.left;
    y.left = x.right;
    if(x.right != nil){
        y.left.p = y;
    }
    if(y.p.left == y){
        y.p.left = x;
        x.p = y.p;
    }else if(y.p.right == y){
        y.p.right = x;
        x.p = y.p;
    }else{
        root = x;
        x.p = nil;
    }
    // y成爲x的右孩子
    y.p = x;
    x.right = y;
    //x的右孩子變成y的左孩子
    //y.left = x.right;

}

private void RBInsert(RedBlackTreeNode z){
    RedBlackTreeNode y = nil;
    RedBlackTreeNode x = root;
    while (x != nil){
        y = x;
        if(z.key < x.key){
            x = x.left;
        }else{
            x = x.right;
        }
    }
    z.p = y;
    if(y == nil){
        root = z;
    }else if(z.key < y.key){
        y.left = z;
    }else{
        y.right = z;
    }
    z.right = nil;
    z.left = nil;
    z.color = colors.red;
    RBInsertFixup(z);
    ++N;

}
private void RBInsertFixup(RedBlackTreeNode z){
    while (z.p.color == colors.red){
        //因爲z的父節點爲紅,z也爲紅,故須要調整
        //首先想把z的父節點set爲紅--> z.p的分支不知足性質5 --> 將z.p.p set爲黑,且將z.uncle set爲紅
        if(z.p == z.p.p.left){//若z.p是z.p.p的左孩子
            RedBlackTreeNode y = z.p.p.right;//z的叔節點
            if(y.color == colors.red){//case 1 : 若是z的叔節點是紅色(與z的父節點顏色同樣)
                z.p.color = colors.black;
                y.color = colors.black;
                z.p.p.color = colors.red;
                z = z.p.p;
                ++z.depth;
            }else if(z == z.p.right){ // case 2 : 若是z的叔節點是黑色,且z是右孩子
                z = z.p;
                LeftRotate(z);//左旋,使得紅色節點z上移
            }
            z.p.color = colors.black;//case 3
            if(z.p != nil) {
                z.p.p.color = colors.red;
                RightRotate(z.p.p);
            }
        }else{//若z.p是z.p.p的右孩子
            RedBlackTreeNode y = z.p.p.left;
            if(y.color == colors.red){//case 1 : 若是z的叔節點是紅色(與z的父節點顏色同樣)
                z.p.color = colors.black;
                y.color = colors.black;
                z.p.p.color = colors.red;
                z = z.p.p;
            }else {
                if (z == z.p.left) { // case 2 : 若是z的叔節點是黑色,且z是左孩子
                    z = z.p;
                    RightRotate(z);//左旋,使得紅色節點z上移
                }
                z.p.color = colors.black;//case 3\
                if(z.p != nil) {
                    z.p.p.color = colors.red;
                    LeftRotate(z.p.p);
                }
            }
        }
    }
    root.color = colors.black;
    root.p = nil;
}

private void RBDelete(RedBlackTreeNode z){

    RedBlackTreeNode y = z;
    colors yOriginalColor = y.color;
    RedBlackTreeNode x = nil;
    if(z.left == nil){ //只有右邊節點
        x = z.right;
        RBTranlant(z,z.right);
    }else if(z.right == nil){//只有左邊節點
        x = z.left;
        RBTranlant(z,z.left);
    }else{//左右都有節點
        y = TreeMinimum(z.right);//z的後繼
        yOriginalColor = y.color;
        x = y.right;
        if(y.p == z){//z.right 就是z的後繼
            x.p = y ;//爲啥?
        }else{
            //後繼是y
            //先用y.right代替y
            RBTranlant(y,y.right);
            //再用y代替z
            y.right = z.right;
            y.right.p = y;
        }
        RBTranlant(z,y);
        y.left = z.left;
        y.left.p = y;
        y.color = z.color;
    }
    if(yOriginalColor == colors.black){
        //當z有一個兒子時,y就是z,x就是z的兒子
        //已知y原爲黑色,即z原來爲黑色。可是
        //z.child(也就是x)替換z後,可能會改變z位置(也就是如今的x)的黑高,故須要調整x
        //      若x是紅色,那麼有可能和原來z.p構成雙紅,以及會破壞x處黑高 --> 把x設置爲黑色便可
        //      若x是黑色,會減少黑高,須要調整

        //當z有兩個兒子時,y是z的後繼,x是y.right
        //z被y替換,已知y是黑色,則會改變z位置(如今y)的黑高。
        //調整:
                    //a.若x是紅色,那麼有可能和原來y.p構成雙紅,以及會破壞x處黑高 --> 把x設置爲黑色便可
                    //b.若x是黑色,因爲y的上移,本分支黑高被破壞,須要調整
        //      2.若z原來是紅色,則y被重置爲紅色。x替換y後,如今x位置處的性質被破壞
        RBDeleteFixup(x);
    }
}
private void RBDeleteFixup(RedBlackTreeNode x){
    while (x != root && x.color == colors.black){
       // bfsTree();
        RedBlackTreeNode w = nil;
        if(x == x.p.left){ //x是一個左孩子
            w = x.p.right;//x的兄弟節點
            if(w.color == colors.red) { //case 1
                colors tempXP = x.p.color;
                x.p.color = w.color;
                w.color = tempXP;
                LeftRotate(x.p);
                w = x.p.right;
            }else{
                if(w.right.color == colors.black){
                    if(w.left.color == colors.black){//case 2
                        w.color = colors.red;
                        x = x.p;
                        --x.depth;
                    }else { // case 3
                        colors temp = w.color;
                        w.color = w.left.color;
                        w.left.color = temp;
                        RightRotate(w);
                        w = x.p.right;
                    }
                }else{// case 4
                    w.color = x.p.color;
                    x.p.color = colors.black;
                    --x.p.depth;
                    ++w.depth;
                    w.right.color = colors.black;
                    LeftRotate(x.p);
                    x =root;
                }
            }
        }else{
            w = x.p.left;//x的兄弟節點
            if(w.color == colors.red) { //case 1
                colors tempXP = x.p.color;
                x.p.color = w.color;
                w.color = tempXP;
                RightRotate(x.p);
                w = x.p.left;
            }else{
                if(w.left.color == colors.black){
                    if(w.right.color == colors.black){//case 2
                        w.color = colors.red;
                        x = x.p;
                    }else { // case 3
                        colors temp = w.color;
                        w.color = w.right.color;
                        w.right.color = temp;
                        LeftRotate(w);
                        w = x.p.left;
                    }
                }else{// case 4
                    w.color = x.p.color;
                    x.p.color = colors.black;
                    w.left.color = colors.black;
                    RightRotate(x.p);
                    x =root;
                }
            }
        }
    }
    x.color = colors.black;
}
private void RBTranlant(RedBlackTreeNode u,RedBlackTreeNode v){//用v替換u
    if(u == u.p.right){//u是u.p的右孩子
        u.p.right = v;
        v.p = u.p;
    }else if( u == u.p.left ){//u是u.p的左孩子孩子
        u.p.left = v;
        v.p = u.p ;
    }else {//u是根節點
        v.p = nil;
        root = v;
    }
}

public RedBlackTree RBJoin(RedBlackTree T1, RedBlackTree T2, int x) throws CloneNotSupportedException {
    RedBlackTreeNode x_root = new RedBlackTreeNode(x);
    x_root.right = T1.root;
    T1.root.p = x_root;

    x_root.left = T2.root;
    T2.root.p = x_root;
int x_N = Math.max(T1.N,T2.N);
    RedBlackTree newTree = new RedBlackTree(x_root);
    newTree.N = x_N;
    T1.nil = newTree.nil;
    T2.nil =  newTree.nil;
    x_root.p = newTree.nil;

    return newTree;
}

private RedBlackTreeNode TreeMinimum(RedBlackTreeNode x){//獲得最小值
    while (x.left != nil){
        x = x.left;
    }
    return x;
}
private RedBlackTreeNode TreeMaximum(RedBlackTreeNode x){//獲得最大值
    while (x.right != nil){
        x = x.right;
    }
    return x;
}

}數組

相關文章
相關標籤/搜索