需求
红黑树实现。由于最近刚好有空闲,秉持着偷懒不学习的程序员不是好会计的原则,重新复习一下红黑树的结构。
实现中的难点问题
红黑树最主要的问题是树的修复,树的修复分为以下几种情况:
父节点与叔叔节点都为红色:
父节点与叔叔节点变黑色
祖父节点变红色
以祖父节点为支点,递归进行树的修复
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