红黑树之插入java实现

红黑树的插入又自顶向下和自底向上两种方式,这里的插入实现是自顶向下的方式。

具体参考的博文地址:http://www.cnblogs.com/xuqiang/archive/2011/05/16/2047001.html

这篇博文将插入的集中case都讲的很清楚了。这里就直接贴代码了,代码有点丑。

package 第一章数据结构实现;

public class RBTree {
    TreeNode head;            //树的头节点
        //创建红色的默认节点,但是未设置父节点
    public TreeNode getNode(int val) {
        TreeNode defaultNode  = new TreeNode(val);
        defaultNode.color = Color.RED;    //默认为红色
        return defaultNode;
    }
        //打印树
    public void printTree(TreeNode node) {
        if(head==null) {
            System.out.println("树是空的,请确认init()方法已经执行!");
            return ;
        }
        if(node==null) return ;
        else {
            //前序遍历
            System.out.print("节点的值:"+node.val+"    节点的颜色:"+node.color);
            if(node.parent!=null) System.out.println("   节点的父节点:"+node.parent.val);
            else System.out.println("    这是根节点");
            printTree(node.left);
            printTree(node.right);
        }
    }
        //===================================================================================================
        //树的初始化
        public void init(int[] arr) {
            for(int i=0;i<arr.length;++i) {
                insert(head,null,arr[i],-1);
            }
        }
        //inset  开始插入 ,lr为0代表left  lr为1代表right lr为-1表示是根节点
    public void  insert(TreeNode head,TreeNode parent,int i,int lr) {
            //如果树为空
            if(head==null) {
                TreeNode x = getNode(i);
                x.parent=parent;
                head = x;        //应该是这里出现问题了,这里其实是把head指向了别处
                if(lr==1) parent.right = head;
                else if(lr==0) parent.left = head;
                insert1(head);
            }
            else {        //递归插入
                if(i>head.val)    insert(head.right,head,i,1);
                if(i<head.val)    insert(head.left,head,i,0);
            }
    }
        //case1:插入的节点为根节点,将插入节点置为红色,前期x的父节点x.parent必须确定下来
    public void insert1(TreeNode  x) {

        if(x.parent==null) {
            x.color = Color.BLACK;
            head = x;                  //将首节点指向x
            return ;
        } else insert2(x);
    }
        //case2:插入的节点不为根节点
        //且插入的节点的父节点为黑色的,那么红黑树是不用调节的
    public void insert2(TreeNode x) {    
        if(x.parent.color==Color.BLACK) return ;
        else insert3(x);
    }
        //case3如果插入节点的父节点为红色 ,违反父子节点都为红色的
        // 如果叔叔节点为红色,只需将叔叔节点和父节点同时设为黑色,同时祖父节点设为红色
        //但这会引入新问题,祖父节点和其自身父节点有可能都为红色,使用尾递归向上上滤
    public void insert3(TreeNode x) {
        TreeNode par = x.parent;    //父节点
        TreeNode gra = par.parent;    //祖父节点
        TreeNode unc = (par==gra.left)? gra.right : gra.left;     //叔叔节点
        if(unc!=null && unc.color==Color.RED) {
            unc.color = Color.BLACK;
            par.color = Color.BLACK;
            gra.color = Color.RED;
            insert1(gra);        //尾递归上滤
        } else insert4(x);
    }
        //case4: 如果叔叔节点为黑色或者null
    public void insert4(TreeNode x) {
        TreeNode par = x.parent;    //父节点
        TreeNode gra = par.parent;    //祖父节点
        TreeNode unc = (par==gra.left)? gra.right : gra.left;     //叔叔节点
            //如果父节点是祖父节点的左节点,但x是父节点的右节点,交换x和其父节点,且x变为其原父节点的父节点
        if(par==gra.left && x==par.right) {
            gra.left = x;
            x.left = par;
            x.parent = gra;
            par.right = null;
            par.parent = x;
            insert5(par);
        }
        //如果父节点是祖父节点的右节点,但是x是父节点的左节点,交换x和其父节点,且x变为祖父节点的右节点
        else if(par==gra.right && x==par.left) {
            gra.right = x;
            x.right = par;
            x.parent = gra;
            par.left = null;
            par.parent = x;
            insert5(par);
        }
        else {
            insert5(x);       //因为这个x节点有可能变为父节点了,所以要在insert5进行判断是否为变换后的父节点
        }
    }
    
    public void insert5(TreeNode x) {
            TreeNode par = x.parent;    //父节点
            TreeNode gra = par.parent;    //祖父节点
            TreeNode ggra = gra.parent; //祖父节点的父节点
            if(x==par.left) {
                gra.left = par.right;
                par.right = gra;
                par.parent = ggra;
                gra.parent = par;
                if(gra.left!=null) gra.left.parent = gra;        //如果节点不为空更新父节点信息
                //ggra.left = par;
                if(ggra==null) head = par;
                else {
                    if(par.val>ggra.val) ggra.right = par;
                    else ggra.left = par;
                }
            }
            else if(x==par.right) {
                //if(x.val==12) System.out.println("12的父节点的左节点:"+par.left.val);
                gra.right = par.left;
                par.left = gra;
                par.parent = ggra;
                gra.parent = par;
                if(gra.right!=null) gra.right.parent = gra;            //要更新父节点信息
                if(ggra==null) head = par;   //根节点要重新指向
                else  {
                    if(par.val>ggra.val) ggra.right = par;
                    else ggra.left = par;
                }
            }
            //颜色变化
            gra.color = Color.RED;
            par.color = Color.BLACK;
    }
    //=======================================================================================================
    public static void main(String[] args) {
        int[] arr = {5,3,1,7,9,6,15,12,14,13};
        RBTree rbt = new RBTree();
        rbt.init(arr);
        rbt.printTree(rbt.head);
    }
        //红黑树节点
    private class TreeNode{
        Color color=Color.RED;
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode parent;
        public TreeNode(int value) {
            val = value;
        }
    }
        //树节点枚举类
    private enum Color{
        RED,BLACK;
    }
    
}
基于int[] arr = {5,3,1,7,9,6,15,12,14,13}构建的红黑树的打印的结果如下:

节点的值:7 节点的颜色:BLACK 这是根节点
节点的值:3 节点的颜色:RED 节点的父节点:7
节点的值:1 节点的颜色:BLACK 节点的父节点:3
节点的值:5 节点的颜色:BLACK 节点的父节点:3
节点的值:6 节点的颜色:RED 节点的父节点:5
节点的值:12 节点的颜色:RED 节点的父节点:7
节点的值:9 节点的颜色:BLACK 节点的父节点:12
节点的值:14 节点的颜色:BLACK 节点的父节点:12
节点的值:13 节点的颜色:RED 节点的父节点:14
节点的值:15 节点的颜色:RED 节点的父节点:14

 

猜你喜欢

转载自www.cnblogs.com/chen-jack/p/10236767.html