1 红黑树逻辑推导图
https://www.processon.com/view/link/5eddac9ce401fd5f2d94f24d
2 节点类-Node
public class Node<E> {
public static final boolean BLACK = true;
public static final boolean RED = false;
// 每一个新增节点都默认为红色
private boolean color = RED;
private Node<E> parent;
private Node<E> leftChild;
private Node<E> rightChild;
private E element;
public Node(E element,Node<E> parent) {
super();
this.element = element;
this.parent = parent;
}
public boolean getColor() {
return color;
}
public void setColor(boolean color) {
this.color = color;
}
public Node<E> getParent() {
return parent;
}
public void setParent(Node<E> parent) {
this.parent = parent;
}
public Node<E> getLeftChild() {
return leftChild;
}
public void setLeftChild(Node<E> leftChild) {
this.leftChild = leftChild;
}
public Node<E> getRightChild() {
return rightChild;
}
public void setRightChild(Node<E> rightChild) {
this.rightChild = rightChild;
}
public E getElement() {
return element;
}
public void setElement(E element) {
this.element = element;
}
//是否是左孩子节点
public boolean isLeftChild(){
return parent != null && this == parent.leftChild;
}
//是否是右孩子节点
public boolean isRightChild(){
return parent != null && this == parent.rightChild;
}
//判断是否是叶子节点
public boolean isLeaf(){
return leftChild == null && rightChild == null;
}
//判断是否有两个子节点
public boolean hasTwoChild(){
return leftChild != null && rightChild != null;
}
/**
* 返回兄弟节点
* 如果要拿到叔父节点
* 则可以调用 parent.sibling()
*/
public Node<E> sibling(){
if(isLeftChild()){
return parent.rightChild;
}
if(isRightChild()){
return parent.leftChild;
}
//即不是左节点,也不是右节点,则没有兄弟节点
//即为根节点
return null;
}
}
3 红黑树实现类-RBTree
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
public class RBTree<E> {
// 比较器,用于比较两个存储对象的大小
private Comparator<E> comparator;
// 树根
private Node<E> root;
// 树中元素的多少
private int size;
public RBTree() {
this(null);
}
public RBTree(Comparator<E> comparator) {
this.comparator = comparator;
}
public void add(E element) {
// 校验传入的参数是否为null
// 如果为null,则抛出异常
elementNotNullCheck(element);
// 校验是否创建了树根
if (root == null) {
root = createNode(element, null);
size++;
// 新添加节点之后的处理
afterAdd(root);
return;
}
// 添加的不是第一个节点
Node<E> parent = root;
Node<E> node = root;
// 用于保存比较的结果
// 大于0,则向右子树
// 等于0,则有相等的元素
// 小于0,则向左子树
int cmp = 0;
// 遍历找到插入位置的父节点
while (node != null) {
cmp = compare(element, node.getElement());
parent = node;
if (cmp > 0) {
node = node.getRightChild();
} else if (cmp < 0) {
node = node.getLeftChild();
} else { // 相等
node.setElement(element);
return;
}
}
// 已经找到了插入位置的父节点 parent
// 新建节点
Node<E> newNode = createNode(element, parent);
if (cmp > 0) {
parent.setRightChild(newNode);
} else {
parent.setLeftChild(newNode);
}
size++;
// 新添加节点之后的处理
afterAdd(newNode);
}
// public E get
//删除节点
public void remove(E element) {
remove(findNode(element));
}
private void remove(Node<E> node) {
if (node == null)
return;
size--;
if (node.hasTwoChild()) { // 度为2的节点
// 找到后继节点
Node<E> s = successor(node);
// 用后继节点的值覆盖度为2的节点的值
node.setElement(s.getElement());
// 删除后继节点
node = s;
}
// 删除node节点(node的度必然是1或者0)
Node<E> replacement = node.getLeftChild() != null ? node.getLeftChild() : node.getRightChild();
if (replacement != null) { // node是度为1的节点
// 更改parent
replacement.setParent(node.getParent());
// 更改parent的left、right的指向
if (node.getParent() == null) { // node是度为1的节点并且是根节点
root = replacement;
} else if (node == node.getParent().getLeftChild()) {
node.getParent().setLeftChild(replacement);
} else { // node == node.parent.right
node.getParent().setRightChild(replacement);
}
// 删除节点之后的处理
afterRemove(replacement);
} else if (node.getParent() == null) { // node是叶子节点并且是根节点
root = null;
// 删除节点之后的处理
afterRemove(node);
} else { // node是叶子节点,但不是根节点
if (node == node.getParent().getLeftChild()) {
node.getParent().setLeftChild(null);
} else { // node == node.parent.right
node.getParent().setRightChild(null);
}
// 删除节点之后的处理
afterRemove(node);
}
}
// 找到前驱节点
protected Node<E> successor(Node<E> node) {
if (node == null)
return null;
// 前驱节点在左子树当中(right.left.left.left....)
Node<E> p = node.getRightChild();
if (p != null) {
while (p.getLeftChild() != null) {
p = p.getLeftChild();
}
return p;
}
// 从父节点、祖父节点中寻找前驱节点
while (node.getParent() != null && node == node.getParent().getRightChild()) {
node = node.getParent();
}
return node.getParent();
}
// 查找元素对应的Node节点
private Node<E> findNode(E element) {
Node<E> node = root;
while (node != null) {
int cmp = compare(element, node.getElement());
if (cmp == 0)
return node;
if (cmp > 0) {
node = node.getRightChild();
} else { // cmp < 0
node = node.getLeftChild();
}
}
return null;
}
private void afterAdd(Node<E> node) {
Node<E> parent = node.getParent();
// 一: 如果父节点为null,则表示变动的节点为根节点
if (null == parent) {
black(node);// 将其置为黑色
return;
}
// 二:如果变动的节点的父节点为黑色,则什么都不用处理
if (isBlack(parent)) {
return;
}
// 三:到此处,说明插入节点的父节点为红色
Node<E> uncle = parent.sibling();
// 祖父节点在这种大的情况下都会要变为红色(仅在最后一步做树根保持黑色的操作)
Node<E> grandParent = red(parent.getParent());
// 1.叔叔节点为红色,即此时父亲节点和叔叔节点都为红色
if (isRed(uncle)) {
// 将叔叔节点与父节点染成黑色,将祖父节点染成红色
black(parent);
black(uncle);
// 将祖父节点染成红色,
red(grandParent);
// 并将其当做新添加节点,向上传递
afterAdd(grandParent);
return;
}
// 2.叔叔节点不为红色,那么只能为空(Nil),不能为黑色节点
// 父节点是左节点
if (parent.isLeftChild()) {
// 插入的节点如果是右孩子,则需要进行左旋操作
if (node.isRightChild()) {
black(node);
rotateLeft(parent);
}
// 插入的节点如果是左孩子,则仅需直接变色
else {
black(parent);
}
// 然后以祖父节点为轴,向右旋转
rotateRight(grandParent);
}
// 父节点是右节点
else {
// 插入的节点如果是左孩子,则先需要右旋操作
if (node.isLeftChild()) {
black(node);
rotateRight(parent);
}
// 插入的节点如果是右孩子,则将父节点变黑
else {
black(parent);
}
// 然后以祖父节点为轴,向左旋转
rotateLeft(grandParent);
}
}
private void afterRemove(Node<E> node) {
// 如果删除的节点是红色的,那么就不用做任何处理
// 用于取代被删除的节点的节点是红色的
if (isRed(node)) {
black(node);
return;
}
// 删除的是黑色的节点
Node<E> parent = node.getParent();
// 1.删除的是黑色的根节点
if (null == parent)
return;
// 2.删除的是黑色的叶子节点
// 判断是否为左孩子节点
boolean left = (parent.getLeftChild() == null) | node.isLeftChild();
// 拿到兄弟节点
Node<E> sibling = left ? parent.getRightChild() : parent.getLeftChild();
if (left) {
// 被删除的黑色节点是左孩子,其兄弟节点在右边
if (isRed(sibling)) {
// 兄弟节点是红色
black(sibling);
red(parent);
rotateLeft(parent);
// 经过旋转之后,兄弟节点发生改变
sibling = parent.getRightChild();
// 后面即可按照兄弟节点为黑色的来处理
}
// 兄弟节点为黑色
if (isBlack(sibling.getLeftChild()) && isBlack(sibling.getRightChild())) {
// 兄弟节点的子节点没有红色节点,即:为黑色节点或者为null
boolean parentIsBlack = isBlack(parent);
black(parent);
red(sibling);
if (parentIsBlack) {
afterRemove(parent);
}
} else {
// 兄弟节点的子节点中至少有一个为红色节点
if (isBlack(sibling.getRightChild())) {
// 兄弟节点的右孩子是null,即为黑色的,不为红色
// 说明红色节点在左边
// 则进行右旋转
rotateRight(sibling);
// 此时兄弟节点发生了改变
sibling = parent.getRightChild();
// 此时即可用兄弟节点的红色孩子节点当做在右边处理
}
// 变色处理(包含了两种情况,将两种情况的颜色统一处理)
color(sibling, colorOf(parent));
black(sibling.getRightChild());
black(parent);
rotateLeft(parent);
}
} else {
// 被删除的黑色节点是右孩子,其兄弟节点在左边
if (isRed(sibling)) {
// 兄弟节点是红色
black(sibling);
red(parent);
rotateRight(parent);
// 经过旋转之后,兄弟节点发生改变
sibling = parent.getLeftChild();
// 后面即可按照兄弟节点为黑色的来处理
}
// 兄弟节点为黑色
if (isBlack(sibling.getLeftChild()) && isBlack(sibling.getRightChild())) {
// 兄弟节点的子节点没有红色节点,即:为黑色节点或者为null
boolean parentIsBlack = isBlack(parent);
black(parent);
red(sibling);
if (parentIsBlack) {
afterRemove(parent);
}
} else {
// 兄弟节点的子节点中至少有一个为红色节点
if (isBlack(sibling.getLeftChild())) {
// 兄弟节点的左孩子是null,即为黑色的,不为红色
// 则进行左旋转
rotateLeft(sibling);
// 此时兄弟节点发生了改变
sibling = parent.getLeftChild();
// 此时即可用兄弟节点的红色孩子节点当做在左边处理
}
// 变色处理(包含了两种情况,将两种情况的颜色统一处理)
color(sibling, colorOf(parent));
black(sibling.getLeftChild());
black(parent);
rotateRight(parent);
}
}
}
protected Node<E> createNode(E element, Node<E> parent) {
return new Node<>(element, parent);
}
// 元素不能为null,否则就抛出异常,中断程序
private void elementNotNullCheck(E element) {
if (element == null) {
throw new IllegalArgumentException("element must not be null");
}
}
// 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2
@SuppressWarnings("unchecked")
private int compare(E e1, E e2) {
if (comparator != null) {
return comparator.compare(e1, e2);
}
return ((Comparable<E>) e1).compareTo(e2);
}
/**
* ========辅助方法============
*/
// ==== 旋转
// 左旋转
private void rotateLeft(Node<E> grand) {
Node<E> parent = grand.getRightChild();
Node<E> child = parent.getLeftChild();
grand.setRightChild(child);
parent.setLeftChild(grand);
afterRotate(grand, parent, child);
}
// 右旋转
private void rotateRight(Node<E> grand) {
Node<E> parent = grand.getLeftChild();
Node<E> child = parent.getRightChild();
grand.setLeftChild(child);
parent.setRightChild(grand);
afterRotate(grand, parent, child);
}
private void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) {
// 让parent称为子树的根节点
parent.setParent(grand.getParent());
if (grand.isLeftChild()) {
grand.getParent().setLeftChild(parent);
} else if (grand.isRightChild()) {
grand.getParent().setRightChild(parent);
} else { // grand是root节点
root = parent;
}
// 更新child的parent
if (child != null) {
child.setParent(grand);
}
// 更新grand的parent
grand.setParent(parent);
}
// ==== 染色
//将节点设置为黑色
public Node<E> black(Node<E> node) {
return color(node, Node.BLACK);
}
//将节点设置为红色
public Node<E> red(Node<E> node) {
return color(node, Node.RED);
}
//设置节点颜色
private Node<E> color(Node<E> node, boolean color) {
if (null != node) {
node.setColor(color);
}
return node;
}
// ========== 判断颜色 =============
//判断是否为黑色
public boolean isBlack(Node<E> node) {
return colorOf(node) == Node.BLACK;
}
//判断是否为红色
public boolean isRed(Node<E> node) {
return colorOf(node) == Node.RED;
}
//获取颜色,如果节点为null,返回黑色
private boolean colorOf(Node<E> node) {
return node == null ? Node.BLACK : node.getColor();
}
/**
* 遍历
*/
// 遍历===前序遍历
public void preOrder() {
System.out.println("前序遍历");
preOrder(root);
}
// 遍历===前序遍历
private void preOrder(Node<E> node) {
if (null == node)
return;
System.out.println((node.getColor() ? "BLACK" : "RED") + node.getElement().toString());
preOrder(node.getLeftChild());
preOrder(node.getRightChild());
}
// 遍历===中序遍历
public void inOrder() {
System.out.println("中序遍历");
inOrder(root);
}
// 遍历===中序遍历
private void inOrder(Node<E> node) {
if (null == node)
return;
inOrder(node.getLeftChild());
System.out.println((node.getColor() ? "BLACK" : "RED") + node.getElement().toString());
inOrder(node.getRightChild());
}
// 遍历===后序遍历
public void afterOrder() {
System.out.println("后序遍历");
afterOrder(root);
}
// 遍历===后序遍历
private void afterOrder(Node<E> node) {
if (null == node)
return;
afterOrder(node.getLeftChild());
afterOrder(node.getRightChild());
System.out.println((node.getColor() ? "BLACK" : "RED") + node.getElement().toString());
}
// 遍历===层序遍历
public void levelOrder() {
System.out.println("层序遍历");
levelOrder(root);
}
// 遍历===层序遍历
private void levelOrder(Node<E> node) {
if(root == null){
System.out.println("树为空");
return;
}
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node<E> head = queue.poll();
if (head.getLeftChild() != null) {
queue.offer(head.getLeftChild());
}
if (head.getRightChild() != null) {
queue.offer(head.getRightChild());
}
System.out.println((head.getColor() ? "BLACK" : "RED") + head.getElement().toString());
}
}
}