红黑树-Java红黑树,算法导论实现版

Posted 数据结构与算法

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了红黑树-Java红黑树,算法导论实现版相关的知识,希望对你有一定的参考价值。


作者丨HustWolf
https://www.jianshu.com/p/263c49cfd37d


不得不说,《算法导论》的伪代码真的是好东西,轻轻一改就是一个船新版本的红黑树具体实现方式。。不多说,直接上码。



。emm 放一个我的小surprise~


【红黑树-Java】红黑树,算法导论实现版


【红黑树-Java】红黑树,算法导论实现版正文


import java.util.Arrays;
import java.util.Random;
import java.util.LinkedList;
import java.util.Queue;


class node{
    private int key;
    node leftChild;
    node rightChild;
    node parent;
    String color = Tree.RED;
    node(){};
    node(int x){
        this.parent = Tree.nil;
        this.rightChild = Tree.nil;
        this.leftChild = Tree.nil;
        this.key=x;
    }
    public int getKey(){
        return this.key;
    }
}

class Tree{
    public static String RED = "RED";
    public static String BLACK = "BLACK";
    node root;
    int size;
    public static node nil = new node(-1);
    Tree(){
        this.size = 0;
        this.root = Tree.nil;
        nil.color = Tree.BLACK;
    }
     node getRoot(){
        return this.root;
    }

    public String toString() {
        System.out.println("输出树形: ");
        Queue<node> queue = new LinkedList<>();
        String out = "";
        queue.add(this.root);
        int x=-10000;
        while (!queue.isEmpty()) {
            node s = queue.poll();
            if (s.getKey()<x) {
                out += " ";
            }
            x=s.getKey();
            out += (s.getKey() + " ");
            if (s.leftChild != Tree.nil)
                queue.add(s.leftChild);
            if (s.rightChild != Tree.nil)
                queue.add(s.rightChild);
        }
        return out;
    }
//    public node minNode(Tree tree){
//        node parent = tree.root;
//        while(parent.leftChild!=Tree.nil)
//            parent=parent.leftChild;
//        return parent;
//    }
//    public node maxNode(Tree tree){
//        node parent = tree.root;
//        while(parent.rightChild!=Tree.nil)
//            parent=parent.rightChild;
//        return parent;
//    }
}

public class TestTree{
    private static node __findNode(node par,int z){
        if (par==Tree.nil || par.getKey() == z)
            return par;
        if (z<par.getKey()) return __findNode(par.leftChild,z);
        else return __findNode(par.rightChild,z);
    }
    static node  findNode(Tree tree,int z){
        node par = tree.getRoot();
        return __findNode(par,z);
    }

    static void RB_TRANSPLANT(Tree tree, node u, node v){
        if (u.parent == Tree.nil) tree.root = v;
        else if (u == u.parent.leftChild){
            u.parent.leftChild = v;
        }
        else {
            u.parent.rightChild = v;
        }
        //this is the BST's condition, but in RB we don't need this, because Tree.nil is always a node instead of NULL
//        if (v!=Tree.nil)
//            u.parent = v.parent;
    }

    static void RB_DELETE_FIXUP(Tree tree, node x){
        while (x != Tree.nil && x.color.equals(Tree.BLACK)){
            if (x == x.parent.leftChild){
                node w = x.parent.rightChild;
                if (w.color.equals(Tree.RED)){
                    w.color = Tree.BLACK;
                    x.parent.color = Tree.RED;
                    LEFT_RORATE(tree,x.parent);
                }
                if (w.leftChild.color.equals(Tree.BLACK) && w.rightChild.color.equals(Tree.BLACK)){
                    w.color = Tree.RED;
                    x = x.parent;
                }
                else if (w.rightChild.color.equals(Tree.BLACK)){
                    w.leftChild.color = Tree.BLACK;
                    w.color = Tree.RED;
                    RIGHT_RORATE(tree,w);
                    w = x.parent.rightChild;
                }
                w.color = x.parent.color;
                x.parent.color = Tree.BLACK;
                w.rightChild.color = Tree.BLACK;
                LEFT_RORATE(tree,x.parent);
                x = tree.getRoot();
            }
            else {
                node w = x.parent.leftChild;
                if (w.color.equals(Tree.RED)){
                    w.color = Tree.BLACK;
                    x.parent.color = Tree.RED;
                    RIGHT_RORATE(tree,x.parent);
                }
                if (w.rightChild.color.equals(Tree.BLACK) && w.leftChild.color.equals(Tree.BLACK)){
                    w.color = Tree.RED;
                    x = x.parent;
                }
                else if (w.leftChild.color.equals(Tree.BLACK)){
                    w.rightChild.color = Tree.BLACK;
                    w.color = Tree.RED;
                    LEFT_RORATE(tree,w);
                    w = x.parent.leftChild;
                }
                w.color = x.parent.color;
                x.parent.color = Tree.BLACK;
                w.leftChild.color = Tree.BLACK;
                RIGHT_RORATE(tree,x.parent);
                x = tree.getRoot();
            }
        }
        x.color = Tree.BLACK;
    }
    static void deleteFromTree(Tree tree, node z){
        tree.size-=1;
        node y = z;
        String originColor = y.color;
        node x = y;
        if (z.leftChild==Tree.nil) {
            x = z.rightChild;
            RB_TRANSPLANT(tree, z, z.rightChild);
        }
        else if (z.rightChild==Tree.nil) {
            x = z.leftChild;
            RB_TRANSPLANT(tree, z, z.leftChild);
        }
        else {
            y = minNode(z.rightChild);
            originColor = y.color;
            x = y.rightChild;
            if (y.parent == z){
                x.parent = y;
            }
            else{
                RB_TRANSPLANT(tree,y,y.rightChild);
                y.rightChild = z.rightChild;
                y.rightChild.parent = y;
            }
            RB_TRANSPLANT(tree,z,y);
            y.leftChild = z.leftChild;
            y.leftChild.parent = y;
            y.color = z.color;
        }
        if (originColor.equals(Tree.BLACK)){
            RB_DELETE_FIXUP(tree,x);
        }
        System.out.println(" Deleted :  "+ z.getKey()+" ");
    }

    private static node minNode(node no){
        node x = no;
        while (x.leftChild!=Tree.nil)
            x=x.leftChild;
        return x;
    }
    public static void insertSort(int []arr, int n){
        for (int i = 1; i < n; ++i)
        {
            int e = arr[i];
            int j=i;
            for (; j > 0; --j)
            {
                if (e < arr[j-1])
                    arr[j] = arr[j-1];
                else
                    break;
            }
            arr[j] = e;
        }
    }

    public static void LEFT_RORATE(Tree T, node x){
        node y = x.rightChild;
        x.rightChild = y.leftChild;
        if (y.leftChild != Tree.nil){
            y.leftChild.parent = x;
        }
        y.parent = x.parent;
        if (x.parent == Tree.nil)
            T.root = y;
        else if (x.parent.leftChild == x)
            x.parent.leftChild = y;
        else x.parent.rightChild = y;
        y.leftChild = x;
        x.parent = y;
        System.out.println("Left Rorate :" + x.getKey()+"<--->"+y.getKey());
    }

    public static void RIGHT_RORATE(Tree T, node y){
        node x = y.leftChild;
        y.leftChild = x.rightChild;
        if (x.rightChild!=Tree.nil)
            x.rightChild.parent = y;
        x.parent = y.parent;
        if (y.parent == Tree.nil)
            T.root = x;
        else if (y.parent.leftChild == y)
            y.parent.leftChild = x;
        else y.parent.rightChild = x;
        x.rightChild = y;
        y.parent = x;
        System.out.println("Right Rorate :" + y.getKey()+"<--->"+x.getKey());
    }

    static void RB_INSERT_FIXUP(Tree tree,node z){
        //while the node's father'color is RED, and the node's color is also RED  which we focus;
        while(z.parent.color.equals(Tree.RED)){
            // now if the node's father is the left node ;
            if (z.parent ==z.parent.parent.leftChild){
                // we get the node'grandfather's another son node whose name is y, and it is the node's uncle we focus
                node y = z.parent.parent.rightChild;
                //if uncle node's color is RED:
                if (y.color.equals(Tree.RED)){
                    // father node's color change to BLACK
                    z.parent.color = Tree.BLACK;
                    //uncle node's color change to BLACK;
                    y.color = Tree.BLACK;
                    //and grandfather node's color change to RED, now Nature 4 is OK!
                    z.parent.parent.color = Tree.RED;
                    // then we can focus on grandfather node now!
                    z = z.parent.parent;
                }
                // if uncle node'color is BLACK and the node we focus is the right node of its father:
                else if (z==z.parent.rightChild){
                    //we now focus on its father
                    z=z.parent;
                    // Rorate left of the new focus node;
                    LEFT_RORATE(tree,z);
                }
                // if uncle node'color is BLACK and the node we focus is the left node of its father:
                else {
                    // change the father'color to BLACK;
                    z.parent.color = Tree.BLACK;
                    //change the grandfather node 's color to RED;
                    z.parent.parent.color = Tree.RED;
                    // Rorate right of the grandfather:
                    RIGHT_RORATE(tree, z.parent.parent);
                }
            }
            else {
                node y = z.parent.parent.leftChild;
                if (y.color.equals(Tree.RED)){
                    z.parent.color = Tree.BLACK;
                    y.color = Tree.BLACK;
                    z.parent.parent.color = Tree.RED;
                    z = z.parent.parent;
                }
                else if (z==z.parent.leftChild){
                    z=z.parent;
                    RIGHT_RORATE(tree,z);
                }
                else{
                    z.parent.color = Tree.BLACK;
                    z.parent.parent.color = Tree.RED;
                    LEFT_RORATE(tree,z.parent.parent);
                }
            }
        }
        tree.root.color = Tree.BLACK;
    }

    public static void insertToTree(Tree tree,int x){
        System.out.println(" Insert into the Tree : "+x);
        tree.size+=1;
        node newnode = new node(x);
        newnode.color = Tree.RED;
        node tmp = tree.getRoot();
        if ( tmp== Tree.nil) {
            tree.root = newnode;
            tree.root.color = Tree.BLACK;
            tree.root.parent =Tree.nil;
            return;
        }
        while(tmp!=Tree.nil) {
            if (x < tmp.getKey()) {
                if (tmp.leftChild==Tree.nil) {
                    newnode.parent = tmp;
                    newnode.leftChild = Tree.nil;
                    tmp.leftChild = newnode;
                    break;
                }
                else
                    tmp = tmp.leftChild;
            }
            else {
                if ( tmp.rightChild==Tree.nil) {
                    newnode.parent = tmp;
                    newnode.rightChild =Tree.nil;
                    tmp.rightChild = newnode;
                    break;
                }
                else
                    tmp = tmp.rightChild;
            }
        }
        RB_INSERT_FIXUP(tree,newnode);
    }

    public static Tree generateTree(int[] arr){
        Tree tree = new Tree();
//        insertSort(arr,arr.length);
        insertToTree(tree,arr[arr.length/2]);
        for (int i=0;i<arr.length;++i) {
            if (i!=arr.length/2) {
                insertToTree(tree,arr[i]);
            }
        }
        return tree;
    }
    public static void main(String[] args{
        double start = System.currentTimeMillis();
        Random rdm = new Random(System.currentTimeMillis());
        int len = 20;
        int [] randomArr = new int[len];
        for(int i=0;i<len;i++)
            randomArr[i] = Math.abs(rdm.nextInt())%(len*5) +1;
        Tree tree = generateTree(randomArr);
        System.out.println(Arrays.toString(randomArr));
        System.out.println(tree.toString());
        deleteFromTree(tree,findNode(tree,randomArr[Math.abs(rdm.nextInt())%(tree.size-2)+1]));
        System.out.println(tree.toString());
        insertToTree(tree,Math.abs(rdm.nextInt())%(len*5) +1);
        System.out.println(tree.toString());
        double end  = System.currentTimeMillis();
        System.out.println("Usage of Time: "+(end-start));
    }
}


基本没啥问题,在原有的二叉搜索树上增加了两个修复方法,另外就是每个节点新增了一个Color属性,还有就是用黑色的Tree.nil全面替代了NULL这个东西,实在是妙不可言!!我他么就不明白了,以前的计算机科学家脑子怎么长的??这么逆天的数据结构都能想出来?!!


运行结果(Output):


Insert into the Tree : 82

Insert into the Tree : 98

Insert into the Tree : 15

Insert into the Tree : 8

Insert into the Tree : 1
Right Rorate :15<--->8

Insert into the Tree : 73

Insert into the Tree : 15
Right Rorate :73<--->15
Left Rorate :15<--->15

Insert into the Tree : 28
Left Rorate :8<--->15
Right Rorate :82<--->15

Insert into the Tree : 90

Insert into the Tree : 2

Insert into the Tree : 47
Left Rorate :28<--->47
Right Rorate :73<--->47

Insert into the Tree : 42

Insert into the Tree : 19

Insert into the Tree : 81

Insert into the Tree : 60

Insert into the Tree : 75
Left Rorate :47<--->73
Right Rorate :82<--->73

Insert into the Tree : 45

Insert into the Tree : 48

Insert into the Tree : 45
Left Rorate :42<--->45

Insert into the Tree : 54
Left Rorate :48<--->54
Right Rorate :60<--->54
[9815817315289024782421981607545484554]
输出树形: 
15 
8 73 
1 15 47 82 
2 28 54 81 98 
19 45 48 60 75 90 
42 45 

Deleted :  90

输出树形: 
15 
8 73 
1 15 47 82 
2 28 54 81 98 
19 45 48 60 75 
42 45 

Insert into the Tree : 51
输出树形: 
15 
8 73 
1 15 47 82 
2 28 54 81 98 
19 45 48 60 75 
42 45 51 

Usage of Time3.0

Process finished with exit code 0


正文之后


溜了溜了,今晚准备骑单车征服长江大桥!emm 值得期待!!


 推荐↓↓↓ 

以上是关于红黑树-Java红黑树,算法导论实现版的主要内容,如果未能解决你的问题,请参考以下文章

算法导论 红黑树 学习 删除

算法导论 红黑树 实现

算法导论 红黑树 实现

码图并茂红黑树

算法导论之红黑树的学习

红黑树初探(算法导论)