既然我们需要手写红黑树,那么我们就要搞清楚什么是红黑树
红黑树(Red Black Tree)是一种自平衡二叉查找树,是在计算机与科学用到的一种数据结构,典型的用途是实现关联数组
基本特征
- 每个节点不是红色就是黑色
- 不可能有连在一起的红色节点
- 根节点都是黑色
- 每个红色节点的两个子节点都是黑色
接下我我们欣赏一颗红黑树
红黑树变换规则:
- 改变节点颜色
- 左旋转
- 右旋转
变色
适用于:
当前父节点是红色且他的祖父节点(父亲的父亲)的另一个子节点也是红色(叔叔节点)
规则:
- 将父亲节点设置为黑色
- 将叔叔节点设置为黑色
- 将祖父也就是父亲的父亲节点设为红色
- 把指针定义到祖父节点 设为当前错做
左旋转
适用于:
当父亲节点为红色的情况下,叔叔的节点为黑色情况下且当前节点是右子树,左旋转以新添加节点的祖父节点作为坐标进行左旋
- 当前插入节点的父亲节点变为黑色
- 祖父节点变为红色
右旋转
适用于:
当父亲节点为红色情况下,叔叔节点为黑色情况下,且当前节点是左子树,右旋转以新添加系欸但的祖父节点作为坐标进行右旋
- 将父亲节点变为黑色
- 将祖父节点变为红色
根据以上的规则我们就开始写代码 首先节点采用内部类去定义,然后颜色的话我们定义成枚举
/**
* Node节点的颜色
*/
public enum NodeColor {
/**
* 红色
*/
red(1, "red"),
/**
* 会给色
*/
black(2, "black");
int color;
String desc;
NodeColor(int color, String desc) {
this.color = color;
this.desc = desc;
}
}
接下来就是我们红黑树的添加和查询最大、最小的操作。没有写删除
public class RedBlackTree {
/**
* 当前的根节点
*/
public Node root;
class Node {
/**
* 节点的内容值
*/
private int value;
/**
* 左节点
*/
private Node left;
/**
* 右节点
*/
private Node right;
/**
* 节点颜色
*/
private NodeColor color;
/**
* 记录当前节点的父亲
* 没有父亲的情况下肯定事根节点
* 祖父事Node.parent.parent
*/
private Node parent;
}
//添加节点
public void insert(int value) {
if (root == null) {//添加根节点
Node newNode = new Node();
//父节点的parent为空
newNode.parent = null;
//根节点为黑色
newNode.color = NodeColor.black;
//设置根节点值
newNode.value = value;
//指定根节点
root = newNode;
} else {
//添加节点
Node node = insertValue(value);
//检查节点(修复旋转)
repairTree(node);
}
}
//插入
public Node insertValue(int value) {
return getPosition(root, value);
}
//修复红黑树
public void repairTree(Node newNode) {
if (newNode.parent.color.equals(NodeColor.red)) {
//如果红红相 进行修复
//当前节 点与父亲结点都为红色,且叔叔节点为红色 开始变色,爷爷下的两个子节点都变成黑色
if ((newNode.parent.parent.left != null && NodeColor.red.equals(newNode.parent.parent.left.color))) {
//叔叔节点改为黑色
newNode.parent.parent.left.color = NodeColor.black;
newNode.parent.color = NodeColor.black;
if (newNode.parent.parent != root) {//爷爷节点不为根节点则变为红色
newNode.parent.parent.color = NodeColor.red;
}
return;
}
//左旋
//父亲节点与当前节点都是红色的情况下,且叔叔节点为黑色或者为空的情况下并且当前节点在右子树才开始左旋
if ((newNode.parent.parent.left == null || NodeColor.black.equals(newNode.parent.parent.color) &&
newNode.parent.right == newNode)) {
leftRotate(newNode.parent.parent);//新节点的爷爷节点是旋转坐标
//旋转完还要修复颜色 祖宗变红色,父亲变黑色
changeColor(newNode);
}
//右旋
//父亲节点与当前节点都是红色的情况下,且叔叔节点为黑色或者为空的情况下并且当前节点在左子树才开始右旋
if ((newNode.parent.parent.right == null || NodeColor.black.equals(newNode.parent.parent.color) &&
newNode.parent.left == newNode)) {
rightRotate(newNode.parent.parent);//新节点的爷爷节点是旋转坐标
//旋转完还要修复颜色 祖宗变红色,父亲变黑色
newNode.parent.parent.color = NodeColor.red;
newNode.parent.color = NodeColor.black;
//旋转玩也需要变色
changeColor(newNode);
}
}
}
public void changeColor(Node newNode) {
newNode.parent.parent.color = NodeColor.red;
newNode.parent.color = NodeColor.black;
if (newNode.parent.color == NodeColor.red) {// 1 2 3 当插入4 旋转完会有bug 还得去判断改变颜色
newNode.parent.color = NodeColor.black;
newNode.parent.parent.color = NodeColor.black;
}
}
//左旋
public void leftRotate(Node node) {
//node是旋转 坐标
Node newNode = node.right;
//旋转之后
node.right = newNode.left;
//改变冲突节点左子树的引用
if (newNode.left != null) {
newNode.parent = node;
}
if (node.parent == null) {
root = newNode;
} else {
if (node.parent.left == node) {//判断是不是左子树
node.parent.left = newNode;//修改引用关系
} else {
node.parent.right = newNode;
}
}
// 修改上位节点的左子树
newNode.left = node;
//旋转坐标节点的父亲等于冲突的节点
node.parent = newNode;
}
//右旋
public void rightRotate(Node node) {
//node是旋转 坐标
Node newNode = node.left;
//旋转之后
node.left = newNode.right;
//改变冲突节点左子树的引用
if (newNode.right != null) {
newNode.parent = node;
}
if (node.parent == null) {
root = newNode;
} else {
if (node.parent.right == node) {//判断是不是右子树
node.parent.right = newNode;//修改引用关系
} else {
node.parent.left = newNode;
}
}
// 修改上位节点的右子树
newNode.right = node;
//旋转坐标节点的父亲等于冲突的节点
node.parent = newNode;
}
public Node getPosition(Node node, int value) {
if (value > node.value) {//往右子树添加
if (node.right == null) {//等于空去赋值添加
Node newNode = new Node();
//父节点的parent为空
newNode.parent = node;
//当前节点默认情况为红色
newNode.color = NodeColor.red;
//设置节点值
newNode.value = value;
//设置父亲节点的右节点
return node.right = newNode;
} else {
return getPosition(node.right, value);
}
} else {//往左子树添加
if (node.left == null) {
Node newNode = new Node();
//父节点的parent为空
newNode.parent = node;
//当前节点默认情况为红色
newNode.color = NodeColor.red;
//设置节点值
newNode.value = value;
//设置父亲节点的左节点
return node.left = newNode;
} else {
return getPosition(node.left, value);
}
}
}
//getMax获取红黑树的最大值
public Integer getMax(Node root) {
if (root != null) {
if (root.right != null) {
getMax(root.right);
} else {
return root.value;
}
}
return null;
}
//getMax获取红黑树的最大值
public Integer getMin(Node root) {
if (root != null) {
if (root.left != null) {
getMax(root.left);
} else {
return root.value;
}
}
return null;
}
}