Comprensión simple de los árboles rojos y negros.

Árbol rojo negro

El árbol rojo-negro es ante todo una estructura de árbol, pero también un árbol binario (cada nodo solo puede tener como máximo dos nodos secundarios, el nodo izquierdo es menor o igual que el nodo primario, el nodo derecho es mayor que el nodo primario), para garantizar los árboles secundarios izquierdo y derecho del árbol Relativamente equilibrados (con la misma profundidad), los árboles rojo y negro usan el color de los nodos para marcar los nodos como rojos o negros. Al calcular la profundidad del árbol, solo se cuenta el número de nodos negros y no se cuenta el número de nodos rojos. Al mismo tiempo, no hay altura variable. Se agregaron variables de color para el nodo padre y el nodo tío.

Características principales (reglas)

Inserte la descripción de la imagen aquí
Al insertar y eliminar, puede activar el ajuste de equilibrio de inserción (método balanceInsertion) o eliminar el método de ajuste de balance (balanceDeletion) del árbol rojo y negro. Los métodos de ajuste incluyen principalmente los siguientes medios: rotación izquierda (método rotateLeft), rotación derecha (método rotateRight) El motivo de la inversión y el ajuste del color es mantener la estructura de datos del árbol rojo-negro.

Implementación de código

声明变量

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());
    }
}

Los resultados muestran:
Inserte la descripción de la imagen aquí
zurdo diestro
Inserte la descripción de la imagen aquí

Si desea tener una comprensión profunda del principio de los árboles rojo-negros, puede depurar y rastrear las conexiones y cambios entre nodos, o puede verificarlo en https://www.cs.usfca.edu/~galles/visualization/Algorithms.html Y aprende.

101 artículos originales publicados · Me gustaron 47 · Visitantes más de 10,000

Supongo que te gusta

Origin blog.csdn.net/TONGZONGE/article/details/104283265
Recomendado
Clasificación