手写红黑树【数据结构】

这篇具有很好参考价值的文章主要介绍了手写红黑树【数据结构】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

2024-3-30 10:52:57

昨天晚上B站看到的视频
00:00~01:00

以下内容源自《【数据结构】》
仅供学习交流使用

版权

禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://jsss-1.blog.csdn.net
禁止其他平台发布时删除以上此话

推荐

我红黑树那么牛,你们凭什么不用我?

手写红黑树

一、理论知识

红黑树的特征

红黑树是一种二叉平衡树,只不过这个平衡不是那么严苛,只需黑平衡就行

  1. 结点分为两种颜色
  2. 根节点是黑色
  3. 叶子结点是黑色的,叶子结点是不存储数据的空结点
  4. 两个红结点不能相连,即红父亲的孩子都是黑色的
  5. 对于任意一个结点,其到叶子结点的路径上的黑色结点数量是一致的

增加

视频

插入结点的颜色是红色的
因为是黑平衡,所以插入红结点有概率不会破坏这个规则

  1. 父为黑,直接插入
  2. 父叔为红,颜色调换
  3. 父红叔黑,颜色调换,再移动
  4. 父子不同向,先掰直,再执行第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

写了一天

迎着日光月光星光,直面风霜雨霜雪霜。文章来源地址https://www.toymoban.com/news/detail-857299.html

到了这里,关于手写红黑树【数据结构】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构——红黑树

    目录 概念 性质 结点的定义  插入 调整 当p是g的左孩子时 当p为g的右孩子时 插入完整代码 红黑树的检测 红黑树完整代码(包括测试数据)   红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是RED或BLACK。 通过对任何一条从根到叶子的路径

    2023年04月09日
    浏览(35)
  • 【数据结构】红黑树

    🐱作者:一只大喵咪1201 🐱专栏:《数据结构与算法》 🔥格言: 你只管努力,剩下的交给时间! 在学习AVL树的时候,我们知道,当修改AVL树的结构(插入,删除)时,会通过旋转来保证平衡因子不超过1,所以频繁的修改结构会导致效率低下,今天我们学习的红黑树就完美解

    2023年04月17日
    浏览(37)
  • 【数据结构-树】红黑树

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年02月07日
    浏览(36)
  • C++数据结构--红黑树

    红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路 径会比其他路径长出俩倍,因而是接近平衡的。如图所示: 每个结点不是红色就是黑色。

    2024年02月09日
    浏览(35)
  • 数据结构--红黑树详解

    红黑树(Red Black Tree)是一种自平衡二叉查找树。它是在 1972 年由 Rudolf Bayer 发明的,当时被称为平衡二叉 B 树(symmetric binary B-trees)。后来,在 1978 年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。 由于其自平衡的特性,保证了最坏情形下在 O(logn) 时间复杂度内完

    2024年02月22日
    浏览(35)
  • 【数据结构】红黑树详解

    目录 前言: 红黑树的概念: 红黑树的性质: 红黑树节点的定义: 红黑树的插入: 情况1:cur为红,p为红,g为黑,u存在且为红  情况2:cur为红,p为红,g为黑,u不存在或者u为黑(p和cur都在其父亲节点同一侧) 情况3:cur为红,p为红,g为黑,u不存在或者u为黑(p和cur在其父

    2024年04月14日
    浏览(44)
  • 数据结构之红黑树

    数据结构可视化演示链接,也就是图片演示的网址 数据结构之AVL Tree 数据结构之B树和B+树 数据结构之Radix和Trie 数据结构之二叉搜索树 红黑树是一种二叉查找树,但在每个结点上增加了一个存储位表示结点的颜色,可以是RED或者BLACK。通过对任何一条从根到叶子的路径上各个

    2024年01月17日
    浏览(34)
  • 数据结构——红黑树详解

    红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树 确保没有一条路径会比其他路径长出两倍 ,因而是接近平衡的。(说它是接近平衡因为它并没有像AVL树的

    2024年04月13日
    浏览(29)
  • 数据结构篇十:红黑树

      红黑树是解决单支树问题的另一种解决方法,它相比较AVL树减少了调整的次数,AVL是一格绝对平衡的树,而红黑树只要求最长路径不超过最短路径的二倍,相比较大大减少了调整次数。在实际中更多的也是使用红黑树,就比如后面的map和set,我们就是以红黑树进行封装的

    2024年03月12日
    浏览(38)
  • 数据结构入门-11-红黑树

    史上最负盛名的平衡二叉树–红黑树,但其实就是2-3树的一种实现 也是BST,每一个节点都有颜色 性质 看 后面推导出来的结论 2-3树 :和红黑树是等价的 满足BST的基本性质,但不是一种二叉树 有两种节点: 2-3 绝对平衡:根节点到叶子节点 一定相同 2.3.1 如何维护绝对平衡

    2023年04月17日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包