Simple understanding of red and black trees

Red black tree

The red-black tree is first of all a tree structure, but also a binary tree (each node can only have at most two child nodes, the left node is less than or equal to the parent node, the right node is greater than the parent node), in order to ensure the left and right child trees of the tree Relatively balanced (with the same depth), the red and black trees use the node coloring method to mark the nodes as red or black. When calculating the depth of the tree, only the number of black nodes is counted, and the number of red nodes is not counted, and there is no variable height. Added color variables for father node and uncle node.

Main features (rules)

Insert picture description here
When inserting and deleting, it may trigger the insertion balance adjustment (balanceInsertion method) or delete balance adjustment (balanceDeletion) method of the red-black tree. The adjustment methods mainly include the following means: left rotation (rotateLeft method), right rotation (rotateRight method) ). The reason for color inversion and adjustment is to maintain the data structure of the red-black tree.

Code

声明变量

package edu.xalead.tree.redTree;

import com.sun.org.apache.regexp.internal.RE;
import sun.reflect.generics.tree.Tree;

public class TreeNode {
    public static Boolean BLACK = false;//黑色
    public static Boolean RED = true;//红色
    private Object data = null;
    private TreeNode left = null;
    private TreeNode right = null;
    private Boolean color = RED;
    private TreeNode parent;


    public TreeNode getParent() {
        return parent;
    }

    public void setParent(TreeNode parent) {
        this.parent = parent;
    }

    public Boolean getColor() {
        return color;
    }

    public void setColor(Boolean color) {
        this.color = color;
    }

    public TreeNode(Object data) {
        this.data = data;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public TreeNode getLeft() {
        return left;
    }

    public void setLeft(TreeNode left) {
        this.left = left;
    }

    public TreeNode getRight() {
        return right;
    }

    public void setRight(TreeNode right) {
        this.right = right;
    }
}
添加数字所需要的接口

package edu.xalead.tree.redTree;

public interface Comp {
    /**
     * 我的规范:只要想往我的BStree树中添加数据,就要实现这个方法,比较大小
     * @param p 要跟自己比较的数据
     * @return 0 相等 1 自己 大于 参数 -1 自己 小于 参数
     */
    public abstract int compare(Object p);
}
比较的实体对象  这里主要是比较年龄 

package edu.xalead.tree.redTree;

public class User implements Comp{
    private int id;
    private int age;
    private String name;

    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int compare(Object p) {
        if(!(p instanceof User)) return -1;
        User u = (User)p;
        if(this.getAge() > u.age) return 1;
        else if(this.getAge() < u.age) return -1;
        return 0;
    }
}
调整树高度的主方法 

package edu.xalead.tree.redTree;

public class RBTree {

    private TreeNode root = null;
    private int size = 0;

    /**
     *
     * @param currentnode 当前准备往左或右添加子节点的节点
     * @param newNode 准备添加的新节点
     */
    private TreeNode f(TreeNode currentnode,TreeNode newNode){
        Comp c = (Comp) currentnode.getData();
        Comp n = (Comp) newNode.getData();
        if(c.compare(n) == -1){
            if(currentnode.getRight() != null){
                f(currentnode.getRight(),newNode);
            }else{
                //右页子节点插入
                currentnode.setRight(newNode);
                newNode.setParent(currentnode);
                insertFixUp(newNode);
            }
        }else if(c.compare(n) == 1){
            if(currentnode.getLeft() != null){
                f(currentnode.getLeft(),newNode);
            }else{
                //左页子节点插入
                currentnode.setLeft(newNode);
                newNode.setParent(currentnode);
                insertFixUp(newNode);
            }
        }else {
            return currentnode;
        }

        return currentnode;
    }
    //调整红黑树
    private void insertFixUp(TreeNode node) {
        TreeNode parent,gparent;

        // 父节点不为空并且父节点是红色时
        while((parent = parent(node)) != null && isRed(parent)){
            gparent = parent(parent);//爷爷节点
            //如果父节点是爷爷节点的左孩子
            if(parent == gparent.getLeft()){
                //叔叔节点是不是红色
                TreeNode uncle = gparent.getRight();
                if(uncle != null && isRed(uncle)){
                    uncle.setColor(TreeNode.BLACK);
                    parent.setColor(TreeNode.BLACK);
                    gparent.setColor(TreeNode.RED);
                    node = gparent; // 爷爷节点作为当前节点
                    continue;
                }

                //叔叔是黑色,且当前节点是右孩子 左旋
                if(parent.getRight() == node){
                    TreeNode temp = parent;
                    left_rotate(parent);
                    parent = node;
                    node = temp;
                }
                //叔叔是黑色,且当前节点是左孩子 右旋
                parent.setColor(TreeNode.BLACK);
                gparent.setColor(TreeNode.RED);
                right_rotate(gparent);

            }else{//如果父节点是爷爷节点的右孩子
                //叔叔节点是红色
                TreeNode uncle = gparent.getLeft();
                if(uncle != null && isRed(uncle)){
                    uncle.setColor(TreeNode.BLACK);
                    parent.setColor(TreeNode.BLACK);
                    gparent.setColor(TreeNode.RED);
                    node = gparent;
                    continue;
                }

                //叔叔是黑色,且当前节点是左孩子 右旋
                if(parent.getLeft() == node){
                    TreeNode temp = parent;
                    right_rotate(parent);
                    parent = node;
                    node = temp;
                }
                //叔叔是黑色,且当前节点是左孩子 左旋
                parent.setColor(TreeNode.BLACK);
                gparent.setColor(TreeNode.RED);
                left_rotate(gparent);
            }
        }
        //            if(this.root.getColor() == TreeNode.RED)
        this.root.setColor(TreeNode.BLACK);
    }

    private boolean isRed(TreeNode parent) {
        if(parent == null || parent.getColor() == TreeNode.BLACK)
            return false;
        return true;
    }

    private boolean isBlack(TreeNode parent) {
        if(parent == null || parent.getColor() == TreeNode.BLACK)
            return true;
        return false;
    }

    private TreeNode parent(TreeNode node) {
        return node.getParent() == null ? null : node.getParent();
    }

    /**
     * 左旋转
     *          a         b
     *        /         /  \
     *      b         c     a
     *    /
     *  c
     * @param
     */
    public TreeNode left_rotate(TreeNode g){
        TreeNode p = g.getRight();
        g.setRight(p.getLeft());
        if(p.getLeft() != null){
            p.getLeft().setParent(g);
        }
        // 把g的父节点设为p的父节点
        p.setParent(g.getParent());

        if(g.getParent() == null){
            this.root = p;
        }else{
            if(g.getParent().getLeft() == g){
                g.getParent().setLeft(p);
            }else{
                g.getParent().setRight(p);
            }
        }

        //把爷节点设为父节点的左孩子
        p.setLeft(g);
        g.setParent(p);
        return p;
    }

    /**
     * 右旋转
     * @param g
     * @return
     */
    public TreeNode right_rotate(TreeNode g){
        TreeNode p = g.getLeft();
        g.setLeft(p.getRight());

        if(p.getRight() != null){
            p.getRight().setParent(g);
        }
        // 把g爷节点父节点设为p
        p.setParent(g.getParent());

        if(g.getParent() == null){
            this.root = p;
        }else{
            if(g.getParent().getRight() == g){
                g.getParent().setRight(p);
            }else{
                g.getParent().setLeft(p);
            }
        }

        //把爷节点设为父节点的右孩子
        p.setRight(g);
        g.setParent(p);
        return p;
    }



    public void add(Comp data){

        TreeNode node = new TreeNode(data);
        if(root == null){
            node.setColor(TreeNode.BLACK);
            root = node;
        }
        else{
            f(this.root,node);
        }
        this.size++;
    }

    public int size(){
        return this.size;
    }
}
测试

package edu.xalead.tree.redTree;

public class Test {
    public static void main(String[] args) {
        RBTree bstree = new RBTree();
        //添加树后左旋
//        bstree.add(new User(1111,20,"张三"));
//        bstree.add(new User(1112,24,"李四"));
//        bstree.add(new User(1112,28,"王麻子"));
//        bstree.add(new User(1113,49,"赵六"));
//        bstree.add(new User(1114,77,"马七"));
        // 添加树后右旋 
        bstree.add(new User(1111,50,"张三"));
        bstree.add(new User(1112,45,"李四"));
        bstree.add(new User(1112,42,"王麻子"));
        bstree.add(new User(1113,30,"赵六"));
        bstree.add(new User(1114,35,"马七"));
        System.out.println(bstree.size());
    }
}

The results show: left-
Insert picture description here
handed right - handed
Insert picture description here

If you want to have a deep understanding of the principle of red-black trees, you can debug and track the connections and changes between nodes, or you can verify it at https://www.cs.usfca.edu/~galles/visualization/Algorithms.html And learn.

101 original articles published · Liked 47 · Visitors 10,000+

Guess you like

Origin blog.csdn.net/TONGZONGE/article/details/104283265