手写红黑树【数据结构】
- 前言
- 版权
- 推荐
- 手写红黑树
- 一、理论知识
- 红黑树的特征
- 增加
- 删除
 
- 二、手写代码
- 初始-树结点
- 初始-红黑树
- 初始-遍历
- 初始-判断红黑树是否有效
- 查找
- 增加-1.父为黑,直接插入
- 增加-2. 父叔为红,颜色调换
- 增加-3. 父红叔黑,颜色调换,再移动
- 增加-4. 父子不同向,先掰直,再执行第3种情况
- 测试增加
- 删除-0 初始化数据
- 删除-1.单个红节点 直接删除
- 删除-3.带有一个子节点
- 删除-4.带有两个子节点
- 删除-2.单个黑结点
- 2.1.1兄黑,对侄红
- 2.1.2兄黑,顺侄红
- 2.1.3 兄黑,双侄黑
 
- 删除-2.单个黑结点 2.2兄红
- 测试删除
 
 
- 附录源码
- 最后
前言
2024-3-30 10:52:57
昨天晚上B站看到的视频
 00:00~01:00
以下内容源自《【数据结构】》
 仅供学习交流使用
版权
禁止其他平台发布时删除以下此话
 本文首次发布于CSDN平台
 作者是CSDN@日星月云
 博客主页是https://jsss-1.blog.csdn.net
 禁止其他平台发布时删除以上此话
推荐
我红黑树那么牛,你们凭什么不用我?
手写红黑树
一、理论知识
红黑树的特征
红黑树是一种二叉平衡树,只不过这个平衡不是那么严苛,只需黑平衡就行
- 结点分为两种颜色
- 根节点是黑色
- 叶子结点是黑色的,叶子结点是不存储数据的空结点
- 两个红结点不能相连,即红父亲的孩子都是黑色的
- 对于任意一个结点,其到叶子结点的路径上的黑色结点数量是一致的
增加
视频
插入结点的颜色是红色的
 因为是黑平衡,所以插入红结点有概率不会破坏这个规则
- 父为黑,直接插入
- 父叔为红,颜色调换
- 父红叔黑,颜色调换,再移动
- 父子不同向,先掰直,再执行第3种情况
删除
视频
https://www.processon.com/view/link/6550422f54fca5688e143664
 
二、手写代码
为了实现简单,加入parent的指针,和isLeaf的标记
可以使用HashMap用来记录每一个叶子结点的父亲结点,即键是叶子,值是父亲;
 也可以直接在Node结点中加入双亲指针。
 根节点的父亲结点是null
 特别注意的是,parent的维护
如果是叶子结点,它的isLeaf的值为true。
初始-树结点
//结点
class TreeNode {
    //true是黑色,false是红色
    boolean color;
    //数据
    Integer data;
    TreeNode left;
    TreeNode right;
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    //是否是叶子结点
    boolean isLeaf;
    //方便实现
    TreeNode parent;
    public TreeNode() {
    }
    public TreeNode(int data) {
        this.data = data;
    }
    public TreeNode(boolean color, Integer data) {
        this.color = color;
        this.data = data;
    }
    public TreeNode(boolean color, Integer data, TreeNode parent) {
        this.color = color;
        this.data = data;
        this.parent = parent;
    }
    public TreeNode(boolean color, Integer data, TreeNode parent, boolean isLeaf) {
        this.color = color;
        this.data = data;
        this.parent = parent;
        this.isLeaf = isLeaf;
    }
//    public TreeNode(Integer data,TreeNode left, TreeNode right) {
//        this.data = data;
//        this.left = left;
//        this.right = right;
//    }
    public boolean isBlack() {
        return color == BLACK;
    }
    @Override
    public String toString() {
        return "TreeNode{" +
                "color=" + color +
                ", data=" + data +
                '}';
    }
}
初始-红黑树
package test;
import java.util.LinkedList;
import java.util.Queue;
public class RedBlackTree {
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    //根结点
    TreeNode root;
    public void initRoot(int data) {
        root = new TreeNode(BLACK, data, null, false);
        TreeNode nil = new TreeNode(BLACK, null, root, true);
        root.left = nil;
        root.right = nil;
    }
    /**
     * 增加
     * 1. 父为黑,直接插入
     * 2. 父叔为红,颜色调换
     * 3. 父红叔黑,颜色调换,再移动
     * 4. 父子不同向,先掰直,再执行第3种情况
     *
     * @param data 数据
     */
    public void add(int data) {
       
    }
    /**
     *  删除
     * 1.单个红节点  直接删除
     * 2.单个黑节点
     *      2.1兄黑
     *         2.1.1 对侄红 (指方向相反的侄节点)
     *               父兄交替旋转、然后按父红兄弟黑换色 (最后一步的换色,父红两兄弟黑,是按交替旋转之后的关系处理。)
     *         2.1.2 顺侄红(指方向相同的侄节点)
     *              兄侄交替旋转,并调换颜色,就会变成对侄红,然后按2.1.1处理
     *         2.1.3 双侄黑
     *              兄变红父变黑,如果父本身就是黑,就以父亲角度按情况2处理
     *
     *      2.2 兄红
     *              父兄交替旋转,并调换颜色,新的兄节点将变黑,在按2.1处理
     * 3.带有一个子节点(当一个节点只有一个子节点时(空叶子除外),该节点必定是黑节点,其子节点必定是红色)
     *      用红子节点值替换,然后直接删除红子节点
     * 4.带有两个子节点!
     *      找到左子树中最靠右的子节点,用该节点值替换,并删除该节点按情况1,2,3处理(左子树中最大的值,也是离其最近的值)
     *
     * @param data 数据
     */
    public void delete(int data) {
    }
    public static void main(String[] args) {
        RedBlackTree tree = new RedBlackTree();
        tree.inorder(tree.root);
//        tree.levelOrder(tree.root);
    }
}
初始-遍历
 //中序遍历
    public void inorder(TreeNode root) {
        if (root == null) {
            return;
        }
        if (!root.left.isLeaf) {
            inorder(root.left);
        }
        System.out.println(root);
        if (!root.right.isLeaf) {
            inorder(root.right);
        }
    }
    //层序遍历
    public void levelOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode cur = queue.poll();
                System.out.print(cur + "\t");
                if (cur.left != null) {
                    queue.add(cur.left);
                }
                if (cur.right != null) {
                    queue.add(cur.right);
                }
            }
            System.out.println();
        }
    }
 
初始-判断红黑树是否有效
    //判断是否是有效的红黑树
    public static boolean isValidRedBlackTree(TreeNode root) {
        if (root == null) {
            return true;
        }
        // 检查根节点是否是黑色
        if (root.color != BLACK) {
            return false;
        }
        // 计算黑高度,并检查红黑平衡
        blackHeight = -1;
        if (!checkBlackBalance(root, 0)) {
            return false;
        }
        // 递归检查每个节点
        return isValidRedBlackSubtree(root);
    }
    private static boolean checkBlackBalance(TreeNode node, int currentBlackHeight) {
        if (node.isLeaf) {
            if (blackHeight == -1) {
                blackHeight = currentBlackHeight;
                return true;
            } else {
                return currentBlackHeight == blackHeight;
            }
        }
        if (node.color == BLACK) {
            currentBlackHeight++;
        }
        return checkBlackBalance(node.left, currentBlackHeight) && checkBlackBalance(node.right, currentBlackHeight);
    }
    private static boolean isValidRedBlackSubtree(TreeNode node) {
        if (node == null) {
            return true;
        }
        // 检查红黑树性质
        if (node.color == RED) {
            if ((node.left != null && node.left.color != BLACK) || (node.right != null && node.right.color != BLACK)) {
                return false;
            }
        }
        // 递归检查左右子树
        return isValidRedBlackSubtree(node.left) && isValidRedBlackSubtree(node.right);
    }
查找
 	/**
     * 查找
     *
     * @param data 数据
     * @return 查找结点,如果差不到就会返回叶子结点
     */
    public TreeNode find(int data) {
        TreeNode find = root;
        while (!find.isLeaf) {
            if (data < find.data) {
                find = find.left;
            } else if(data==find.data){
                return find;
            } else if (data > find.data) {
                find = find.right;
            }
        }
        return find;
    }
增加-1.父为黑,直接插入
   /**
     * 增加
     * 1. 父为黑,直接插入
     * 2. 父叔为红,颜色调换
     * 3. 父红叔黑,颜色调换,再移动
     * 4. 父子不同向,先掰直,再执行第3种情况
     *
     * @param data 数据
     */
    public void add(int data) {
        if (root == null) {
            initRoot(data);
            return;
        }
        TreeNode find = find(data);
        if (!find.isLeaf) {
            System.out.println("不能插入相同数据的结点");
            return;
        }
        TreeNode parent = find.parent;
        TreeNode newNode = new TreeNode(RED, data, parent);
        TreeNode nil = new TreeNode(BLACK, null, newNode, true);
        newNode.left = nil;
        newNode.right = nil;
        if (data < parent.data) {
            parent.left = newNode;
        } else {
            parent.right = newNode;
        }
        //1.父为黑,直接插入
        if (parent.isBlack()) {
            //不需要额外的操作
        } else {
        	//跳转2...
        }
增加-2. 父叔为红,颜色调换
    TreeNode grandpa = parent.parent;
            TreeNode uncle = grandpa.left != parent ? grandpa.left : grandpa.right;
            //2. 父叔为红,颜色调换
            if (!uncle.isBlack()) {
                parent.color = BLACK;
                uncle.color = BLACK;
                grandpa.color = RED;
                //如果爷爷是根节点
                if (grandpa == root) {
                    grandpa.color = BLACK;
                    return;
                }
                //爷爷变成红色后,它的父叔可能为红
                TreeNode cur=grandpa;
                parent=cur.parent;
                grandpa=parent.parent;
                
                if (parent==null||grandpa==null){
                    return;
                }
                uncle=grandpa.left != parent ? grandpa.left : grandpa.right;
                while (!cur.isBlack()&&!parent.isBlack()&&!uncle.isBlack()){
                    parent.color = BLACK;
                    uncle.color = BLACK;
                    grandpa.color = RED;
                    //如果爷爷是根节点
                    if (grandpa == root) {
                        grandpa.color = BLACK;
                        break;
                    }
                    cur=grandpa;
                    parent=cur.parent;
                    grandpa=parent.parent;
                    uncle=grandpa.left != parent ? grandpa.left : grandpa.right;
                }
            } else {
            	//跳转3...
            }
                
增加-3. 父红叔黑,颜色调换,再移动
				//跳转3...
                boolean right1 = data > parent.data;
                boolean right2 = parent.data > grandpa.data;
                boolean direct1 = right1 && right2;
                boolean left1 = data < parent.data;
                boolean left2 = parent.data < grandpa.data;
                boolean direct2 = left1 && left2;
                //3. 父红叔黑,颜色调换,再移动
                if (direct1 || direct2) {
                    op(data, parent, grandpa);
                } else {
                	//跳转4...
                }
    public void op(int data, TreeNode parent, TreeNode grandpa) {
        boolean right1 = data > parent.data;
        boolean right2 = parent.data > grandpa.data;
        boolean direct1 = right1 && right2;
        boolean left1 = data < parent.data;
        boolean left2 = parent.data < grandpa.data;
        boolean direct2 = left1 && left2;
        boolean tmp = grandpa.color;
        grandpa.color = parent.color;
        parent.color = tmp;
        TreeNode grandpaPa = grandpa.parent;
        if (parent.data < grandpaPa.data) {
            grandpaPa.left = parent;
        } else {
            grandpaPa.right = parent;
        }
        parent.parent = grandpaPa;
        if (direct1) {
            parent.left = grandpa;
            grandpa.parent = parent;
        } else if (direct2) {
            parent.right = grandpa;
            grandpa.parent = parent;
        }
        grandpa.left = new TreeNode(BLACK, null, grandpa, true);
        grandpa.right = new TreeNode(BLACK, null, grandpa, true);
    }
增加-4. 父子不同向,先掰直,再执行第3种情况
					//跳转4...
 					//4. 父子不同向,先掰直,再执行第3种情况
                    if (left1) {
                        grandpa.right = newNode;
                        newNode.right = parent;
                    }
                    if (right1) {
                        grandpa.left = newNode;
                        newNode.left = parent;
                    }
                    newNode.parent = grandpa;
                    parent.parent = newNode;
                    TreeNode newNil = new TreeNode(BLACK, null, parent, true);
                    parent.left = newNil;
                    parent.right = newNil;
                    op(parent.data, newNode, grandpa);
测试增加
    public static void main(String[] args) {
        RedBlackTree tree = new RedBlackTree();
        testAdd(tree);
    }
    private static void testAdd(RedBlackTree tree) {
        tree.add(157);//0
        tree.add(12);//1
        tree.add(200);//1
        tree.add(250);//2
        tree.add(260);//3
        tree.add(220);//2
        tree.add(210);//4
        tree.add(11);//1
        tree.add(10);//3
        tree.add(7);//2
        tree.add(9);//4
        tree.inorder(tree.root);
//        tree.levelOrder(tree.root);
        System.out.println(isValidRedBlackTree(tree.root));
    }
11、10、7、9的插入图如下
 


2024-3-30 15:35:56
删除-0 初始化数据

    public static void main(String[] args) {
        RedBlackTree tree = new RedBlackTree();
//        testAdd(tree);
        initData(tree);
    }
    private static void initData(RedBlackTree tree) {
        int[] nums={430,261,636,
        95,344,559,822,
        37,131,330,369,499,594,705,981,
        262,345,485,664,818};
        for (int i = 0; i < nums.length; i++) {
            tree.add(nums[i]);
        }
//        tree.inorder(tree.root);
        tree.levelOrder(tree.root);
        System.out.println(isValidRedBlackTree(tree.root));
    }
删除-1.单个红节点 直接删除
 /**
     *  删除
     * 1.单个红节点  直接删除
     * 2.单个黑节点
     *      2.1兄黑
     *         2.1.1 对侄红 (指方向相反的侄节点)
     *               父兄交替旋转、然后按父红兄弟黑换色 (最后一步的换色,父红两兄弟黑,是按交替旋转之后的关系处理。)
     *         2.1.2 顺侄红(指方向相同的侄节点)
     *              兄侄交替旋转,并调换颜色,就会变成对侄红,然后按2.1.1处理
     *         2.1.3 双侄黑
     *              兄变红父变黑,如果父本身就是黑,就以父亲角度按情况2处理
     *
     *      2.2 兄红
     *              父兄交替旋转,并调换颜色,新的兄节点将变黑,在按2.1处理
     * 3.带有一个子节点(当一个节点只有一个子节点时(空叶子除外),该节点必定是黑节点,其子节点必定是红色)
     *      用红子节点值替换,然后直接删除红子节点
     * 4.带有两个子节点
     *      找到左子树中最靠右的子节点,用该节点值替换,并删除该节点按情况1,2,3处理(左子树中最大的值,也是离其最近的值)
     *
     * @param data 数据
     */
    public void delete(int data) {
        TreeNode find = find(data);
        if (find.isLeaf){
            System.out.println("没有找到");
            return;
        }
        //1.单个红节点
        if (!find.isBlack()){
            if (find.left.isLeaf&&find.right.isLeaf){
                TreeNode parent = find.parent;
                TreeNode nil=new TreeNode(BLACK,null,parent,true);
                if (data<parent.data){
                    parent.left=nil;
                }else {
                    parent.right=nil;
                }
            }else {
                //4.带有两个子节点
               
            }
        }else {
            //3.带有一个子节点,用红子节点值替换,然后直接删除红子节点
            
        }
    }
删除-3.带有一个子节点
			//3.带有一个子节点,用红子节点值替换,然后直接删除红子节点
            if (find.left.isLeaf&&!find.right.isBlack()){
                find.data=find.right.data;
                find.right= new TreeNode(BLACK,null,find,true);
            }else if (find.right.isLeaf&&!find.left.isBlack()){
                find.data=find.left.data;
                find.left= new TreeNode(BLACK,null,find,true);
            } 
删除-4.带有两个子节点
			else if (!find.left.isLeaf&&!find.right.isLeaf){//4.带有两个子节点
                TreeNode replace = findReplace(find);
                delete(replace.data);
                find.data= replace.data;
            }else {//2.单个黑结点
            
    /**
     * 查找替代的结点
     * 中序遍历线索树的直接前驱结点
     * @param node 删除的结点
     * @return 查找替代
     */
    public TreeNode findReplace(TreeNode node) {
        TreeNode left = node.left;
        while (!left.isLeaf) {
            left=left.right;
        }
        return left.parent;
    }
删除-2.单个黑结点
2.1.1兄黑,对侄红
  				TreeNode parent=find.parent;
                TreeNode brother=parent.left!=find?parent.left:parent.right;
                boolean left=find.data<parent.data;
                //对侄
                TreeNode duiNephew=left?brother.right:brother.left;
                //顺侄
                TreeNode shunNephew=left?brother.left:brother.right;
                if (brother.isBlack()){//2.1兄黑
                    //2.1.1 对侄红
                    TreeNode duiNephew=left?brother.right:brother.left;
                    if (!duiNephew.isBlack()){
                        //父兄交替旋转
                        TreeNode grandpa=parent.parent;
                        if (brother.data<grandpa.data){
                            grandpa.left=brother;
                        }else {
                            grandpa.right=brother;
                        }
                        brother.parent=grandpa;
                        if (left){
                            brother.left=parent;
                        }else {
                            brother.right=parent;
                        }
                        parent.parent=brother;
                        TreeNode nil=new TreeNode(BLACK,null,parent,true);
                        parent.left=nil;
                        parent.right=nil;
                        //并调换颜色
                        brother.color=RED;
                        duiNephew.color=BLACK;
                        parent.color=BLACK;
                    }else if (!shunNephew.isBlack()){//2.1.2 顺侄红
                    
                    }else if (brother.left.isBlack()&&brother.right.isBlack()){//2.1.3 双侄黑
                    
                    }
                else{//兄红
                
                }
     
                   
2.1.2兄黑,顺侄红
                        //兄侄交替旋转,并调换颜色,就会变成对侄红,
                        if (brother.data< parent.data){
                            parent.left=shunNephew;
                            shunNephew.left=brother;
                        }else {
                            parent.right=shunNephew;
                            shunNephew.right=brother;
                        }
                        shunNephew.parent=parent;
                        brother.parent=shunNephew;
                        TreeNode nil=new TreeNode(BLACK,null,brother,true);
                        brother.left=nil;
                        brother.right=nil;
                        brother.color=RED;
                        shunNephew.color=BLACK;
                        delete(data);
2.1.3 兄黑,双侄黑
                        //兄变红父变黑,如果父本身就是黑,就以父亲角度按情况2处理
                        brother.color=RED;
                        parent.color=BLACK;
                        TreeNode nil=new TreeNode(BLACK,null,parent,true);
                        if (find.data< parent.data){
                            parent.left=nil;
                        }else {
                            parent.right=nil;
                        }
删除-2.单个黑结点 2.2兄红
					//父兄交替旋转,并调换颜色,新的兄节点将变黑,在按2.1处理
                    TreeNode grandpa=parent.parent;
                    if (brother.data<grandpa.data){
                        grandpa.left=brother;
                    }else {
                        grandpa.right=brother;
                    }
                    brother.parent=grandpa;
                    TreeNode tmp;
                    if (data<parent.data){
                        tmp=brother.left;
                        brother.left=parent;
                    }else {
                        tmp=brother.right;
                        brother.right=parent;
                    }
                    parent.parent=brother;
                    if (data<parent.data){
                        parent.left=find;
                        parent.right=tmp;
                    }else {
                        parent.left=tmp;
                        parent.right=find;
                    }
                    brother.color=BLACK;
                    parent.color=RED;
                    delete(data);
测试删除
    public static void main(String[] args) {
        RedBlackTree tree = new RedBlackTree();
//        testAdd(tree);
        initData(tree);
        testDelete(tree);
        
        tree.levelOrder(tree.root);
        System.out.println(isValidRedBlackTree(tree.root));
    }
    private static void testDelete(RedBlackTree tree) {
        tree.delete(262);//1
        tree.delete(818);//1
        tree.delete(705);//3
        tree.delete(369);//3
        tree.add(346);
        tree.delete(430);//4
        tree.delete(594);//2.1.1
        tree.add(570);
        tree.delete(485);//2.1.1
        tree.add(565);
        tree.delete(499);//2.1.2
        tree.add(335);
        tree.delete(345);//2.1.2
        tree.delete(559);//2.1.3
        tree.delete(570);
        tree.delete(565);//2.2
        tree.delete(37);
        tree.delete(131);
        tree.delete(95);//2.2
    }

附录源码
package test;
import java.util.LinkedList;
import java.util.Queue;
public class RedBlackTree {
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    //根结点
    TreeNode root;
    public void initRoot(int data) {
        root = new TreeNode(BLACK, data, null, false);
        TreeNode nil = new TreeNode(BLACK, null, root, true);
        root.left = nil;
        root.right = nil;
    }
    /**
     * 增加
     * 1. 父为黑,直接插入
     * 2. 父叔为红,颜色调换
     * 3. 父红叔黑,颜色调换,再移动
     * 4. 父子不同向,先掰直,再执行第3种情况
     *
     * @param data 数据
     */
    public void add(int data) {
        if (root == null) {
            initRoot(data);
            return;
        }
        TreeNode find = find(data);
        if (!find.isLeaf) {
            System.out.println("不能插入相同数据的结点");
            return;
        }
        TreeNode parent = find.parent;
        TreeNode newNode = new TreeNode(RED, data, parent);
        TreeNode nil = new TreeNode(BLACK, null, newNode, true);
        newNode.left = nil;
        newNode.right = nil;
        if (data < parent.data) {
            parent.left = newNode;
        } else {
            parent.right = newNode;
        }
        //1.父为黑,直接插入
        if (parent.isBlack()) {
            //不需要额外的操作
        } else {
            TreeNode grandpa = parent.parent;
            TreeNode uncle = grandpa.left != parent ? grandpa.left : grandpa.right;
            //2. 父叔为红,颜色调换
            if (!uncle.isBlack()) {
                parent.color = BLACK;
                uncle.color = BLACK;
                grandpa.color = RED;
                //如果爷爷是根节点
                if (grandpa == root) {
                    grandpa.color = BLACK;
                    return;
                }
                //爷爷变成红色后,它的父叔可能为红
                TreeNode cur=grandpa;
                parent=cur.parent;
                grandpa=parent.parent;
                if (parent==null||grandpa==null){
                    return;
                }
                uncle=grandpa.left != parent ? grandpa.left : grandpa.right;
                while (!cur.isBlack()&&!parent.isBlack()&&!uncle.isBlack()){
                    parent.color = BLACK;
                    uncle.color = BLACK;
                    grandpa.color = RED;
                    //如果爷爷是根节点
                    if (grandpa == root) {
                        grandpa.color = BLACK;
                        break;
                    }
                    cur=grandpa;
                    parent=cur.parent;
                    grandpa=parent.parent;
                    uncle=grandpa.left != parent ? grandpa.left : grandpa.right;
                }
            } else {
                boolean right1 = data > parent.data;
                boolean right2 = parent.data > grandpa.data;
                boolean direct1 = right1 && right2;
                boolean left1 = data < parent.data;
                boolean left2 = parent.data < grandpa.data;
                boolean direct2 = left1 && left2;
                //3. 父红叔黑,颜色调换,再移动
                if (direct1 || direct2) {
                    op(data, parent, grandpa);
                } else {
                    //4. 父子不同向,先掰直,再执行第3种情况
                    if (left1) {
                        grandpa.right = newNode;
                        newNode.right = parent;
                    }
                    if (right1) {
                        grandpa.left = newNode;
                        newNode.left = parent;
                    }
                    newNode.parent = grandpa;
                    parent.parent = newNode;
                    TreeNode newNil = new TreeNode(BLACK, null, parent, true);
                    parent.left = newNil;
                    parent.right = newNil;
                    op(parent.data, newNode, grandpa);
                }
            }
        }
    }
    public void op(int data, TreeNode parent, TreeNode grandpa) {
        boolean right1 = data > parent.data;
        boolean right2 = parent.data > grandpa.data;
        boolean direct1 = right1 && right2;
        boolean left1 = data < parent.data;
        boolean left2 = parent.data < grandpa.data;
        boolean direct2 = left1 && left2;
        boolean tmp = grandpa.color;
        grandpa.color = parent.color;
        parent.color = tmp;
        TreeNode grandpaPa = grandpa.parent;
        if (parent.data < grandpaPa.data) {
            grandpaPa.left = parent;
        } else {
            grandpaPa.right = parent;
        }
        parent.parent = grandpaPa;
        if (direct1) {
            parent.left = grandpa;
            grandpa.parent = parent;
        } else if (direct2) {
            parent.right = grandpa;
            grandpa.parent = parent;
        }
        grandpa.left = new TreeNode(BLACK, null, grandpa, true);
        grandpa.right = new TreeNode(BLACK, null, grandpa, true);
    }
    /**
     *  删除
     * 1.单个红节点  直接删除
     * 2.单个黑节点
     *      2.1兄黑
     *         2.1.1 对侄红 (指方向相反的侄节点)
     *               父兄交替旋转、然后按父红兄弟黑换色 (最后一步的换色,父红两兄弟黑,是按交替旋转之后的关系处理。)
     *         2.1.2 顺侄红(指方向相同的侄节点)
     *              兄侄交替旋转,并调换颜色,就会变成对侄红,然后按2.1.1处理
     *         2.1.3 双侄黑
     *              兄变红父变黑,如果父本身就是黑,就以父亲角度按情况2处理
     *
     *      2.2 兄红
     *              父兄交替旋转,并调换颜色,新的兄节点将变黑,在按2.1处理
     * 3.带有一个子节点(当一个节点只有一个子节点时(空叶子除外),该节点必定是黑节点,其子节点必定是红色)
     *      用红子节点值替换,然后直接删除红子节点
     * 4.带有两个子节点
     *      找到左子树中最靠右的子节点,用该节点值替换,并删除该节点按情况1,2,3处理(左子树中最大的值,也是离其最近的值)
     *
     * @param data 数据
     */
    public void delete(int data) {
        TreeNode find = find(data);
        if (find.isLeaf){
            System.out.println("没有找到");
            return;
        }
        //1.单个红节点
        if (!find.isBlack()){
            if (find.left.isLeaf&&find.right.isLeaf){
                TreeNode parent = find.parent;
                TreeNode nil=new TreeNode(BLACK,null,parent,true);
                if (data<parent.data){
                    parent.left=nil;
                }else {
                    parent.right=nil;
                }
            }else {
                //4.带有两个子节点
                TreeNode replace = findReplace(find);
                delete(replace.data);
                find.data= replace.data;
            }
        }else {
            //3.带有一个子节点,用红子节点值替换,然后直接删除红子节点
            if (find.left.isLeaf&&!find.right.isBlack()){
                find.data=find.right.data;
                find.right= new TreeNode(BLACK,null,find,true);
            }else if (find.right.isLeaf&&!find.left.isBlack()){
                find.data=find.left.data;
                find.left= new TreeNode(BLACK,null,find,true);
            } else if (!find.left.isLeaf&&!find.right.isLeaf){//4.带有两个子节点
                TreeNode replace = findReplace(find);
                delete(replace.data);
                find.data= replace.data;
            }else {//2.单个黑结点
                TreeNode parent=find.parent;
                TreeNode brother=parent.left!=find?parent.left:parent.right;
                boolean left=find.data<parent.data;
                //对侄
                TreeNode duiNephew=left?brother.right:brother.left;
                //顺侄
                TreeNode shunNephew=left?brother.left:brother.right;
                if (brother.isBlack()){//2.1兄黑
                    //2.1.1 对侄红
                    if (!duiNephew.isBlack()){
                        //父兄交替旋转
                        TreeNode grandpa=parent.parent;
                        if (brother.data<grandpa.data){
                            grandpa.left=brother;
                        }else {
                            grandpa.right=brother;
                        }
                        brother.parent=grandpa;
                        if (left){
                            brother.left=parent;
                        }else {
                            brother.right=parent;
                        }
                        parent.parent=brother;
                        TreeNode nil=new TreeNode(BLACK,null,parent,true);
                        parent.left=nil;
                        parent.right=nil;
                        //并调换颜色
                        brother.color=RED;
                        duiNephew.color=BLACK;
                        parent.color=BLACK;
                    } else if (!shunNephew.isBlack()){//2.1.2 顺侄红
                        //兄侄交替旋转,并调换颜色,就会变成对侄红,
                        if (brother.data< parent.data){
                            parent.left=shunNephew;
                            shunNephew.left=brother;
                        }else {
                            parent.right=shunNephew;
                            shunNephew.right=brother;
                        }
                        shunNephew.parent=parent;
                        brother.parent=shunNephew;
                        TreeNode nil=new TreeNode(BLACK,null,brother,true);
                        brother.left=nil;
                        brother.right=nil;
                        brother.color=RED;
                        shunNephew.color=BLACK;
                        delete(data);
                    } else if (brother.left.isBlack()&&brother.right.isBlack()){//2.1.3 双侄黑
                        //兄变红父变黑,如果父本身就是黑,就以父亲角度按情况2处理
                        brother.color=RED;
                        parent.color=BLACK;
                        TreeNode nil=new TreeNode(BLACK,null,parent,true);
                        if (find.data< parent.data){
                            parent.left=nil;
                        }else {
                            parent.right=nil;
                        }
                    }
                }else {//2.2兄红
                    //父兄交替旋转,并调换颜色,新的兄节点将变黑,在按2.1处理
                    TreeNode grandpa=parent.parent;
                    if (brother.data<grandpa.data){
                        grandpa.left=brother;
                    }else {
                        grandpa.right=brother;
                    }
                    brother.parent=grandpa;
                    TreeNode tmp;
                    if (data<parent.data){
                        tmp=brother.left;
                        brother.left=parent;
                    }else {
                        tmp=brother.right;
                        brother.right=parent;
                    }
                    parent.parent=brother;
                    if (data<parent.data){
                        parent.left=find;
                        parent.right=tmp;
                    }else {
                        parent.left=tmp;
                        parent.right=find;
                    }
                    brother.color=BLACK;
                    parent.color=RED;
                    delete(data);
                }
            }
        }
    }
    /**
     * 查找
     *
     * @param data 数据
     * @return 查找结点,如果差不到就会返回叶子结点
     */
    public TreeNode find(int data) {
        TreeNode find = root;
        while (!find.isLeaf) {
            if (data < find.data) {
                find = find.left;
            } else if(find.data.equals(data)){
                return find;
            } else if (data > find.data) {
                find = find.right;
            }
        }
        return find;
    }
    /**
     * 查找替代的结点
     * 中序遍历线索树的直接前驱结点
     * @param node 删除的结点
     * @return 查找替代
     */
    public TreeNode findReplace(TreeNode node) {
        TreeNode left = node.left;
        while (!left.isLeaf) {
            left=left.right;
        }
        return left.parent;
    }
    //中序遍历
    public void inorder(TreeNode root) {
        if (root == null) {
            return;
        }
        if (!root.left.isLeaf) {
            inorder(root.left);
        }
        System.out.println(root);
        if (!root.right.isLeaf) {
            inorder(root.right);
        }
    }
    //层序遍历
    public void levelOrder(TreeNode root) {
        if (root == null) {
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode cur = queue.poll();
                System.out.print(cur + "\t");
                if (cur.left != null) {
                    queue.add(cur.left);
                }
                if (cur.right != null) {
                    queue.add(cur.right);
                }
            }
            System.out.println();
        }
    }
    private static int blackHeight = -1;
    //判断是否是有效的红黑树
    public static boolean isValidRedBlackTree(TreeNode root) {
        if (root == null) {
            return true;
        }
        // 检查根节点是否是黑色
        if (root.color != BLACK) {
            return false;
        }
        // 计算黑高度,并检查红黑平衡
        blackHeight = -1;
        if (!checkBlackBalance(root, 0)) {
            return false;
        }
        // 递归检查每个节点
        return isValidRedBlackSubtree(root);
    }
    private static boolean checkBlackBalance(TreeNode node, int currentBlackHeight) {
        if (node.isLeaf) {
            if (blackHeight == -1) {
                blackHeight = currentBlackHeight;
                return true;
            } else {
                return currentBlackHeight == blackHeight;
            }
        }
        if (node.color == BLACK) {
            currentBlackHeight++;
        }
        return checkBlackBalance(node.left, currentBlackHeight) && checkBlackBalance(node.right, currentBlackHeight);
    }
    private static boolean isValidRedBlackSubtree(TreeNode node) {
        if (node == null) {
            return true;
        }
        // 检查红黑树性质
        if (node.color == RED) {
            if ((node.left != null && node.left.color != BLACK) || (node.right != null && node.right.color != BLACK)) {
                return false;
            }
        }
        // 递归检查左右子树
        return isValidRedBlackSubtree(node.left) && isValidRedBlackSubtree(node.right);
    }
    
    public static void main(String[] args) {
        RedBlackTree tree = new RedBlackTree();
//        testAdd(tree);
        initData(tree);
        testDelete(tree);
        tree.levelOrder(tree.root);
        System.out.println(isValidRedBlackTree(tree.root));
    }
    private static void testDelete(RedBlackTree tree) {
        tree.delete(262);//1
        tree.delete(818);//1
        tree.delete(705);//3
        tree.delete(369);//3
        tree.add(346);
        tree.delete(430);//4
        tree.delete(594);//2.1.1
        tree.add(570);
        tree.delete(485);//2.1.1
        tree.add(565);
        tree.delete(499);//2.1.2
        tree.add(335);
        tree.delete(345);//2.1.2
        tree.delete(559);//2.1.3
        tree.delete(570);
        tree.delete(565);//2.2
        tree.delete(37);
        tree.delete(131);
        tree.delete(95);//2.2
    }
    private static void initData(RedBlackTree tree) {
        int[] nums={430,261,636,
        95,344,559,822,
        37,131,330,369,499,594,705,981,
        262,345,485,664,818};
        for (int i = 0; i < nums.length; i++) {
            tree.add(nums[i]);
        }
//        tree.inorder(tree.root);
//        tree.levelOrder(tree.root);
//        System.out.println(isValidRedBlackTree(tree.root));
    }
    private static void testAdd(RedBlackTree tree) {
        tree.add(157);//0
        tree.add(12);//1
        tree.add(200);//1
        tree.add(250);//2
        tree.add(260);//3
        tree.add(220);//2
        tree.add(210);//4
        tree.add(11);//1
        tree.add(10);//3
        tree.add(7);//2
        tree.add(9);//4
        tree.inorder(tree.root);
//        tree.levelOrder(tree.root);
        System.out.println(isValidRedBlackTree(tree.root));
    }
}
//结点
class TreeNode {
    //true是黑色,false是红色
    boolean color;
    //数据
    Integer data;
    TreeNode left;
    TreeNode right;
    private static final boolean RED = false;
    private static final boolean BLACK = true;
    //是否是叶子结点
    boolean isLeaf;
    //方便实现
    TreeNode parent;
    public TreeNode() {
    }
    public TreeNode(int data) {
        this.data = data;
    }
    public TreeNode(boolean color, Integer data) {
        this.color = color;
        this.data = data;
    }
    public TreeNode(boolean color, Integer data, TreeNode parent) {
        this.color = color;
        this.data = data;
        this.parent = parent;
    }
    public TreeNode(boolean color, Integer data, TreeNode parent, boolean isLeaf) {
        this.color = color;
        this.data = data;
        this.parent = parent;
        this.isLeaf = isLeaf;
    }
//    public TreeNode(Integer data,TreeNode left, TreeNode right) {
//        this.data = data;
//        this.left = left;
//        this.right = right;
//    }
    public boolean isBlack() {
        return color == BLACK;
    }
    @Override
    public String toString() {
        return "TreeNode{" +
                "color=" + color +
                ", data=" + data +
                '}';
    }
}
最后
2024-3-30 23:05:13
写了一天
迎着日光月光星光,直面风霜雨霜雪霜。


















