喵星之旅-沉睡的猫咪-红黑树

Posted kittybunny

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了喵星之旅-沉睡的猫咪-红黑树相关的知识,希望对你有一定的参考价值。

本文建立在两个基础之上:1、会基本的java编程;2、对二叉树是认识的

具体的分类情况分析参看最下方视频连接:初级算法部分

红黑树概念

当一颗二叉树符合了如下要求后,就称之为红黑树:

1、节点具有颜色,只有红色或者黑色,只能是唯一颜色

2、二叉树是有序的,即每一个节点的左节点存值都比当前节点值小,右节点值比当前节点值不小

3、根结点和叶子节点为黑色,叶子节点值的是树的末端没有子节点的节点下一层,是不存有值的,叶子节点是空节点

4、如果一个节点是红色的,父节点必须是黑色的,也就是不存在连续的双红

5、对于黑色节点完全平衡,即从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

红黑树java实现

1、前置工作

创建一个树类

 

public class RBTree{
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    private RBTreeNode root;
}

 

创建节点类

 

private static class RBTreeNode {
        private int value;
        private RBTreeNode up;
        private RBTreeNode left;
        private RBTreeNode right;
        private boolean color;
}

 

节点类中编写遍历方法,方便bug查询和结果展示

 

        public void show(int count, String lor) {
            String s = "";
            for (int i = 0; i < count; i++) {
                s += "        ";
            }
            s += lor + "[value=" + value + ", color=" + color + "]";
            System.out.println(s);
            if (left != null) {
                left.show(count + 1, "l");
            }
            if (right != null) {
                right.show(count + 1, "r");
            }
        }        

 

2、插入,由于旋转操作是针对于一般化的二叉树操作,只是方便复用,不会造成效率提升(无论这里的编码还是执行),这里不再封装左右旋转方法,针对红黑树直接处理。

 

/**
     *  添加节点
     * @param n
     */
    public void add(int n) {
        // 创建红色节点
        RBTreeNode node = new RBTreeNode(n);
        // 查找要插入的位置,并且插入
        insert(node, n);
        // 调整双红问题
        tobalance(node);
    }

 

    private void insert(RBTreeNode node, int n) {
        RBTreeNode p = this.root;
        if (p == null) {
            this.root = node;
            return;
        }
        for (;;) {
            if (p.value > n) {
                if (p.left == null) {
                    p.left = node;
                    node.up = p;
                    break;
                } else {
                    p = p.left;
                    continue;
                }
            } else {
                if (p.right == null) {
                    p.right = node;
                    node.up = p;
                    break;
                } else {
                    p = p.right;
                    continue;
                }
            }
        }
    }
技术图片
    /**
     *  调整双红问题
     * @param node
     */
    private void tobalance(RBTreeNode node) {
        RBTreeNode now = node;
        RBTreeNode up = null;
        RBTreeNode upup = null;
        RBTreeNode top = null;
        RBTreeNode n1 = null;
        RBTreeNode n2 = null;
        RBTreeNode n3 = null;
        RBTreeNode n4 = null;
        // 获得分类情况
        for (boolean flag = true; flag;) {
            int n = sortForInsert(now);
            switch (n) {//含义参看上面方法说明
            case 1:
                now.color = RBTree.BLACK;
                flag = false;
                
                break;
            case 2:
                flag = false;
                
                break;
            case 3:
                up = now.up;
                upup = up.up;
                upup.color = RBTree.RED;
                upup.left.color = RBTree.BLACK;
                upup.right.color = RBTree.BLACK;
                now = upup;
                
                break;

            case 4:
                up = now.up;
                upup = up.up;
                upup.color = RBTree.RED;
                upup.left.color = RBTree.BLACK;
                upup.right.color = RBTree.BLACK;
                now = upup;
                
                break;
            case 5:
                up = now.up;
                upup = up.up;
                n1 = up.right;
                n2 = upup.right;
                top = upup.up;
                
                up.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                
                up.right = upup;
                upup.up = up;
                upup.left = n1;
                if (n1 != null) {
                    n1.up = upup;
                }
                upup.right = n2;
                if (n2 != null) {
                    n2.up = upup;
                }
                if (top == null) {
                    root = up;
                    root.up = null;
                } else {
                    up.up = top;
                    if (top.left == upup) {
                        top.left = up;
                    } else {
                        top.right = up;
                    }
                }
                flag = false;
                
                break;
            case 6:
                up = now.up;
                upup = up.up;
                
                top = upup.up;
                n1 = up.left;
                n2 = now.left;
                n3 = now.right;
                n4 = upup.right;
                
                now.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                
                up.right = n2;
                if (n2 !=null) {
                    n2.up = up;
                }
                up.up = now;
                now.left = up;
                now.right = upup;
                upup.up = now;
                upup.left = n3;
                if (n3 != null) {
                    n3.up = upup;
                }
                if (top == null) {
                    root = now;
                    root.up = null;
                } else {
                    now.up = top;
                    if (top.left == upup) {
                        top.left = now;
                    } else {
                        top.right = now;
                    }
                }
                flag = false;
                
                break;
            case 7:
                up = now.up;
                upup = up.up;
                top = upup.up;
                n2 = now.left;
                n3 = now.right;
                now.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                
                upup.right = n2;
                if (n2 != null) {
                    n2.up = upup;
                }
                upup.up = now;
                now.left = upup;
                up.up = now;
                now.right = up;
                up.left = n3;
                if (n3 != null) {
                    n3.up = up;
                }
                if (top == null) {
                    root = now;
                    root.up = null;
                } else {
                    now.up = top;
                    if (top.left == upup) {
                        top.left = now;
                    } else {
                        top.right = now;
                    }
                }
                flag = false;
                
                break;
            case 8:
                up = now.up;
                upup = up.up;
                top = upup.up;
                n2 = up.left;
                up.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                upup.right = n2;
                if (n2 != null) {
                    n2.up = upup;
                }
                upup.up = up;
                up.left = upup;

                if (top == null) {
                    root = up;
                    root.up = null;
                } else {
                    up.up = top;
                    if (top.left == upup) {
                        top.left = up;
                    } else {
                        top.right = up;
                    }
                }
                flag = false;
                
                break;
            }
        }
        root.color = RBTree.BLACK;
    }
View Code
    /**
     *  对于插入操作,判断分类情况
     * @param node
     * @return 分类情况:1-根结点,2-父节点黑色, 3-叔叔节点红色,父节点红色,父节点是左节点,4-叔叔节点红色,父节点红色,父节点是右节点,
     *         5-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点左孩子,6-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点右孩子,
     *         7-叔叔节点不是红色,父节点红色,父节点是 右节点,当前节点是父节点左孩子,8-叔叔节点不是红色,父节点红色,父节点是
     *         右节点,当前节点是父节点右孩子
     */
    private int sortForInsert(RBTreeNode node) {
        if (node.up == null) {
            return 1;
        } else if (node.up.color == RBTree.BLACK) {
            return 2;
        } else {
            RBTreeNode up = node.up;
            RBTreeNode upup = up.up;
            if (up == upup.left) {// 父节点是左节点
                if (upup.right == null || upup.right.color == RBTree.BLACK) {
                    if (up.left == node) {
                        return 5;
                    } else {
                        return 6;
                    }
                } else {
                    return 3;
                }
            } else {// 父节点是右节点
                if (upup.left == null || upup.left.color == RBTree.BLACK) {
                    if (up.left == node) {
                        return 7;
                    } else {
                        return 8;
                    }
                } else {
                    return 4;
                }
            }
        }

    }

3、删除

待续

 

测试结果

package club.kittybunn.test;

import club.kittybunny.RBTree;

public class Test {
    public static void main(String[] args) {
        RBTree tree = new RBTree();
        tree.add(1);
        tree.add(2);
        tree.add(3);
        tree.add(4);
        tree.add(5);
        tree.add(6);
        tree.add(7);
        tree.add(8);
        tree.add(9);
        tree.add(10);

        tree.show(0, "");

    }
}
[value=4, color=true]
        l[value=2, color=true]
                l[value=1, color=true]
                r[value=3, color=true]
        r[value=6, color=true]
                l[value=5, color=true]
                r[value=8, color=false]
                        l[value=7, color=true]
                        r[value=9, color=true]
                                r[value=10, color=false]

 


最终完整代码

 

 

 

 

package club.kittybunny;

import java.util.TreeMap;

import javax.sound.sampled.ReverbType;

/**
 * 
 * @author bunny~~我是兔子我会喵,我叫喵星兔。
 *
 */
public class RBTree {
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    private RBTreeNode root;


    /**
     *  添加节点
     * @param n
     */
    public void add(int n) {
        // 创建红色节点
        RBTreeNode node = new RBTreeNode(n);
        // 查找要插入的位置,并且插入
        insert(node, n);
        // 调整双红问题
        tobalance(node);
    }
    
    /**
     *  调整双红问题
     * @param node
     */
    private void tobalance(RBTreeNode node) {
        RBTreeNode now = node;
        RBTreeNode up = null;
        RBTreeNode upup = null;
        RBTreeNode top = null;
        RBTreeNode n1 = null;
        RBTreeNode n2 = null;
        RBTreeNode n3 = null;
        RBTreeNode n4 = null;
        // 获得分类情况
        for (boolean flag = true; flag;) {
            int n = sortForInsert(now);
            switch (n) {//含义参看上面方法说明
            case 1:
                now.color = RBTree.BLACK;
                flag = false;
                
                break;
            case 2:
                flag = false;
                
                break;
            case 3:
                up = now.up;
                upup = up.up;
                upup.color = RBTree.RED;
                upup.left.color = RBTree.BLACK;
                upup.right.color = RBTree.BLACK;
                now = upup;
                
                break;

            case 4:
                up = now.up;
                upup = up.up;
                upup.color = RBTree.RED;
                upup.left.color = RBTree.BLACK;
                upup.right.color = RBTree.BLACK;
                now = upup;
                
                break;
            case 5:
                up = now.up;
                upup = up.up;
                n1 = up.right;
                n2 = upup.right;
                top = upup.up;
                
                up.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                
                up.right = upup;
                upup.up = up;
                upup.left = n1;
                if (n1 != null) {
                    n1.up = upup;
                }
                upup.right = n2;
                if (n2 != null) {
                    n2.up = upup;
                }
                if (top == null) {
                    root = up;
                    root.up = null;
                } else {
                    up.up = top;
                    if (top.left == upup) {
                        top.left = up;
                    } else {
                        top.right = up;
                    }
                }
                flag = false;
                
                break;
            case 6:
                up = now.up;
                upup = up.up;
                
                top = upup.up;
                n1 = up.left;
                n2 = now.left;
                n3 = now.right;
                n4 = upup.right;
                
                now.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                
                up.right = n2;
                if (n2 !=null) {
                    n2.up = up;
                }
                up.up = now;
                now.left = up;
                now.right = upup;
                upup.up = now;
                upup.left = n3;
                if (n3 != null) {
                    n3.up = upup;
                }
                if (top == null) {
                    root = now;
                    root.up = null;
                } else {
                    now.up = top;
                    if (top.left == upup) {
                        top.left = now;
                    } else {
                        top.right = now;
                    }
                }
                flag = false;
                
                break;
            case 7:
                up = now.up;
                upup = up.up;
                top = upup.up;
                n2 = now.left;
                n3 = now.right;
                now.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                
                upup.right = n2;
                if (n2 != null) {
                    n2.up = upup;
                }
                upup.up = now;
                now.left = upup;
                up.up = now;
                now.right = up;
                up.left = n3;
                if (n3 != null) {
                    n3.up = up;
                }
                if (top == null) {
                    root = now;
                    root.up = null;
                } else {
                    now.up = top;
                    if (top.left == upup) {
                        top.left = now;
                    } else {
                        top.right = now;
                    }
                }
                flag = false;
                
                break;
            case 8:
                up = now.up;
                upup = up.up;
                top = upup.up;
                n2 = up.left;
                up.color = RBTree.BLACK;
                upup.color = RBTree.RED;
                upup.right = n2;
                if (n2 != null) {
                    n2.up = upup;
                }
                upup.up = up;
                up.left = upup;

                if (top == null) {
                    root = up;
                    root.up = null;
                } else {
                    up.up = top;
                    if (top.left == upup) {
                        top.left = up;
                    } else {
                        top.right = up;
                    }
                }
                flag = false;
                
                break;
            }
        }
        root.color = RBTree.BLACK;
    }

    /**
     *  对于插入操作,判断分类情况
     * @param node
     * @return 分类情况:1-根结点,2-父节点黑色, 3-叔叔节点红色,父节点红色,父节点是左节点,4-叔叔节点红色,父节点红色,父节点是右节点,
     *         5-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点左孩子,6-叔叔节点不是红色,父节点红色,父节点是左节点,当前节点是父节点右孩子,
     *         7-叔叔节点不是红色,父节点红色,父节点是 右节点,当前节点是父节点左孩子,8-叔叔节点不是红色,父节点红色,父节点是
     *         右节点,当前节点是父节点右孩子
     */
    private int sortForInsert(RBTreeNode node) {
        if (node.up == null) {
            return 1;
        } else if (node.up.color == RBTree.BLACK) {
            return 2;
        } else {
            RBTreeNode up = node.up;
            RBTreeNode upup = up.up;
            if (up == upup.left) {// 父节点是左节点
                if (upup.right == null || upup.right.color == RBTree.BLACK) {
                    if (up.left == node) {
                        return 5;
                    } else {
                        return 6;
                    }
                } else {
                    return 3;
                }
            } else {// 父节点是右节点
                if (upup.left == null || upup.left.color == RBTree.BLACK) {
                    if (up.left == node) {
                        return 7;
                    } else {
                        return 8;
                    }
                } else {
                    return 4;
                }
            }
        }

    }

    private void insert(RBTreeNode node, int n) {
        RBTreeNode p = this.root;
        if (p == null) {
            this.root = node;
            return;
        }
        for (;;) {
            if (p.value > n) {
                if (p.left == null) {
                    p.left = node;
                    node.up = p;
                    break;
                } else {
                    p = p.left;
                    continue;
                }
            } else {
                if (p.right == null) {
                    p.right = node;
                    node.up = p;
                    break;
                } else {
                    p = p.right;
                    continue;
                }
            }
        }
    }

    private static class RBTreeNode {
        private int value;
        private RBTreeNode up;
        private RBTreeNode left;
        private RBTreeNode right;
        private boolean color;

        /**
         * 颜色默认红色
         * 
         * @param value 节点值
         */
        public RBTreeNode(int value) {
            super();
            this.value = value;
            this.color = RBTree.RED;
        }

        /**
         * 
         * @param count 树深度
         * @param lor   是父节点的左还是右节点,l-左,r-右
         */
        public void show(int count, String lor) {
            String s = "";
            for (int i = 0; i < count; i++) {
                s += "        ";
            }
            s += lor + "[value=" + value + ", color=" + color + "]";
            System.out.println(s);
            if (left != null) {
                left.show(count + 1, "l");
            }
            if (right != null) {
                right.show(count + 1, "r");
            }
        }

    }

    public void show(int i, String string) {
        root.show(0, "");
    }
}

 

 

 

 

 

以上是关于喵星之旅-沉睡的猫咪-红黑树的主要内容,如果未能解决你的问题,请参考以下文章

喵星之旅-沉睡的猫咪-原型模式

喵星之旅-沉睡的猫咪-门面模式

喵星之旅-沉睡的猫咪-面向对象的设计原则

喵星之旅目录

红黑树之旅 | 手撕红黑树视频

喵星之旅-狂奔的兔子-docker安装和基本使用