手写红黑树(插入)

需求

红黑树实现。由于最近刚好有空闲,秉持着偷懒不学习的程序员不是好会计的原则,重新复习一下红黑树的结构。

实现中的难点问题

红黑树最主要的问题是树的修复,树的修复分为以下几种情况:

父节点与叔叔节点都为红色:

父节点与叔叔节点变黑色
祖父节点变红色
以祖父节点为支点,递归进行树的修复

LL双红:

父节点变黑色
祖父节点变红色
以祖父节点为支点,进行右旋

RL双红:

以父节点为支点,进行右旋
以父节点为支点,递归进行树的修复

RR双红:

父节点变黑色
祖父节点变红色
以祖父节点为支点,进行左旋

LR双红:

以父节点为支点,进行左旋
以父节点为支点,递归进行树的修复

step1: 先写一个树节点对象

package com.tfxing.index.dataStructure;

import com.tfxing.index.common.utils.handle.MyJsonUtilPlus;
import com.tfxing.index.enums.RBTreeColorEnum;
import lombok.Data;

/**
 * @author :tanfuxing
 * @date :2023/1/10
 * @description :
 */
@Data
public class TreeNode<T> {
    
    private Boolean color;
    
    private T value;
    
    //父节点
    private TreeNode<T> parent;
    
    //左子树
    private TreeNode<T> left;
    
    //右子树
    private TreeNode<T> right;

    public TreeNode(T t,boolean color) {
        this.value = t;
        this.color = color;
    }
    
    public void setParent(TreeNode<T> parent) {
        this.parent = parent;
    }

    public void setLeft(TreeNode<T> left) {
        this.left = left;
    }
    
    public void setRight(TreeNode<T> right) {
        this.right = right;
    }
    
    public int getHashCode() {
        return value.hashCode();
    }
    
    public String toString() {
        String result = "{\"value\":\"%s\", \n \"color\":\"%s\", \n \"left\":%s, \n \"right\":%s}";
        result = String.format(result,this.value, RBTreeColorEnum.getDescByKey(this.color),getToString(this.left),getToString(this.right));
        return result;
    }

    /**
     * 返回toString字符串
     * @param treeNode
     * @return
     */
    private String getToString(TreeNode<T> treeNode) {
        return null == treeNode ? null : treeNode.toString();
    }
}

step2:再写一个红黑树的封装对象

package com.tfxing.index.dataStructure;

import com.tfxing.index.enums.RBTreeColorEnum;
import lombok.Data;

/**
 * @author :tanfuxing
 * @date :2023/1/10
 * @description :
 */
@Data
public class RBTree<T> {
    
    //根节点
    private TreeNode<T> root;
    
    public RBTree() {}

    /**
     * 插入元素
     * @param t
     */
    public void add(T t) {
        TreeNode<T> currentNode = createTreeNode(t);
        insertTree(currentNode,this.root);
        
    }

    /**
     * 插入树节点
     * @param currentNode
     */
    private void insertTree(TreeNode<T> currentNode, TreeNode treeNode) {
        
        if(isNull(treeNode)) {
            if(isNull(this.root)) {
                this.root = currentNode;
            } else {
                TreeNode<T> parentNode = currentNode.getParent();
                if(compare(parentNode,currentNode)) {
                    parentNode.setLeft(currentNode);
                } else {
                    parentNode.setRight(currentNode);
                }
            }
            //树修复
            treeFixHandle(currentNode);
            return;
        }
        
        currentNode.setParent(treeNode);
        if(compare(treeNode,currentNode)) {
            insertTree(currentNode,treeNode.getLeft());
        } else {
            insertTree(currentNode,treeNode.getRight());
        }
        
    }

    /**
     * 对象是否为空
     * @param t
     * @return
     */
    private <T> boolean isNull(T t) {
        return null == t;
    }

    /**
     * 树修复
     * @param currentNode
     */
    private void treeFixHandle(TreeNode<T> currentNode) {
        if(isRoot(currentNode)) {
            colorChangeHandle(currentNode,RBTreeColorEnum.BLACK.getKey());
        } else if(isRed(currentNode.getParent())) {
            TreeNode<T> parentNode = currentNode.getParent();
            TreeNode<T> grandPaNode = parentNode.getParent();
            TreeNode<T> uncleNode = getUncleNode(currentNode);
            //如果父节点和叔叔节点都为红色
            if(isRed(parentNode) && isRed(uncleNode)) {
                colorChangeHandle(parentNode,RBTreeColorEnum.BLACK.getKey());
                colorChangeHandle(uncleNode,RBTreeColorEnum.BLACK.getKey());
                colorChangeHandle(grandPaNode,RBTreeColorEnum.RED.getKey());
                treeFixHandle(grandPaNode);
            } else {
                if(isLeftNode(currentNode)) {
                    if(isLeftNode(parentNode)) { //LL双红
                        colorChangeHandle(parentNode,RBTreeColorEnum.BLACK.getKey());
                        colorChangeHandle(grandPaNode,RBTreeColorEnum.RED.getKey());
                        rightRotation(grandPaNode);
                    } else { //RL双红
                        rightRotation(parentNode);
                        treeFixHandle(parentNode);
                    }
                } else if(isRightNode(currentNode)) { 
                    if(isRightNode(parentNode)) { //RR双红
                        colorChangeHandle(parentNode,RBTreeColorEnum.BLACK.getKey());
                        colorChangeHandle(grandPaNode,RBTreeColorEnum.RED.getKey());
                        leftRotation(grandPaNode);
                    } else { //LR双红
                        leftRotation(parentNode);
                        treeFixHandle(parentNode);
                    }
                }
            }
        }
    }

    /**
     * 当前节点是否为右子节点
     * @param currentNode
     * @return
     */
    private boolean isRightNode(TreeNode<T> currentNode) {
        TreeNode<T> parentNode = currentNode.getParent();
        return parentNode.getRight() == currentNode;
    }

    /**
     * 当前节点是否为红色
     * @param currentNode
     * @return
     */
    private boolean isRed(TreeNode<T> currentNode) {
        //如果为空,则为黑色
        if(isNull(currentNode)) return false;
        return !currentNode.getColor();
    }

    /**
     * 变色:指定颜色
     * @param currentNode
     * @param color
     */
    private void colorChangeHandle(TreeNode<T> currentNode, boolean color) {
        currentNode.setColor(color);
    }

    /**
     * 获取当前节点的叔叔节点
     * @param currentNode
     * @return
     */
    private TreeNode<T> getUncleNode(TreeNode<T> currentNode) {
        TreeNode<T> parentNode = currentNode.getParent();
        TreeNode<T> grandPaNode = parentNode.getParent();
        TreeNode<T> uncleNode = isLeftNode(parentNode) ? grandPaNode.getRight() : grandPaNode.getLeft();
        return uncleNode;
    }

    /**
     * 右旋
     * @param currentNode
     */
    private void rightRotation(TreeNode<T> currentNode) {
        TreeNode<T> parentNode = currentNode.getParent();
        TreeNode<T> leftNode = currentNode.getLeft();
        TreeNode<T> leftRightNode = leftNode.getRight();
        if (!isNull(parentNode)) {
            if(isLeftNode(currentNode)) {
                parentNode.setLeft(leftNode);
            } else {
                parentNode.setRight(leftNode);
            }
        }
        leftNode.setParent(parentNode);
        leftNode.setRight(currentNode);
        currentNode.setParent(leftNode);
        currentNode.setLeft(leftRightNode);
        
        if(isRoot(currentNode)) {
            this.root = leftNode;
        }
    }

    /**
     * 左旋
     * @param currentNode
     */
    private void leftRotation(TreeNode<T> currentNode) {
        TreeNode<T> parentNode = currentNode.getParent();
        TreeNode<T> rightNode = currentNode.getRight();
        TreeNode<T> rightLeftNode = rightNode.getLeft();
        if(!isNull(parentNode)) {
            if(isLeftNode(currentNode)) {
                parentNode.setLeft(rightNode);
            } else {
                parentNode.setRight(rightNode);
            }
        }
        rightNode.setParent(parentNode);
        rightNode.setLeft(currentNode);
        currentNode.setParent(rightNode);
        currentNode.setRight(rightLeftNode);
        
        if(isRoot(currentNode)) {
            this.root = rightNode;
        }
    }

    /**
     * 当前节点是否为左子节点
     * @param currentNode
     * @return
     */
    private boolean isLeftNode(TreeNode<T> currentNode) {
        TreeNode<T> parentNode = currentNode.getParent();
        return parentNode.getLeft() == currentNode;
    }
    

    /**
     * 是否是根节点
     * @param currentNode
     * @return
     */
    private boolean isRoot(TreeNode<T> currentNode) {
        return this.root == currentNode;
    }

    /**
     * 比较:第一个值是否大于第二个值
     * @param currentNode
     * @param treeNode
     * @return
     */
    private boolean compare(TreeNode<T> currentNode, TreeNode<T> treeNode) {
        return currentNode.getHashCode() > treeNode.getHashCode() ? true : false;
    }

    /**
     * 创建树节点
     * @param t
     * @return
     */
    private TreeNode<T> createTreeNode(T t) {
        return new TreeNode<>(t, RBTreeColorEnum.RED.getKey());
    }
    
    public String toString() {
        return this.root.toString();
    }
}


step3:颜色枚举类

	package com.tfxing.index.enums;

/**
 * @author :tanfuxing
 * @date :2023/1/10
 * @description :
 */
public enum RBTreeColorEnum {
    
    BLACK(true,"BLACK"),
    
    RED(false,"RED");
    
    private final Boolean color;
    
    private final String desc;
    
    
    private RBTreeColorEnum(boolean color, String desc) {
        this.color = color;
        this.desc = desc;
    }
    
    public static String getDescByKey(Boolean color) {
        String desc = "";
        for (RBTreeColorEnum rbTreeColorEnum : RBTreeColorEnum.values()) {
            if(rbTreeColorEnum.color.equals(color)) {
                desc = rbTreeColorEnum.desc;
                break;
            }
        }
        return desc;
    }

    public boolean getKey() {
        return this.color;
    }
    
    public String getDesc() {
        return this.desc;
    }
    
}

    }

step4:测试效果

@Test
    void testRBTree() {
        RBTree<Integer> rbTree = new RBTree<>();
        rbTree.add(324);
        rbTree.add(245);
        rbTree.add(643);
        rbTree.add(211);
        rbTree.add(200);
        rbTree.add(192);
        rbTree.add(195);
        rbTree.add(985);
        rbTree.add(728);
        rbTree.add(120);
        rbTree.add(159);
        System.out.println(rbTree);
    }
    

输出结果

{
	"value": "211",
	"color": "BLACK",
	"left": {
		"value": "195",
		"color": "RED",
		"left": {
			"value": "159",
			"color": "BLACK",
			"left": {
				"value": "120",
				"color": "RED",
				"left": null,
				"right": null
			},
			"right": {
				"value": "192",
				"color": "RED",
				"left": null,
				"right": null
			}
		},
		"right": {
			"value": "200",
			"color": "BLACK",
			"left": null,
			"right": null
		}
	},
	"right": {
		"value": "324",
		"color": "RED",
		"left": {
			"value": "245",
			"color": "BLACK",
			"left": null,
			"right": null
		},
		"right": {
			"value": "728",
			"color": "BLACK",
			"left": {
				"value": "643",
				"color": "RED",
				"left": null,
				"right": null
			},
			"right": {
				"value": "985",
				"color": "RED",
				"left": null,
				"right": null
			}
		}
	}
}

效果展示图

在这里插入图片描述

其他

红黑树插入效果演示网址:
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值