文章目录

  • 代码框架
  • 添加(12种情况)
  • 修复性质4(添加在父节点为红色的情况)
  • LL(RR)两种
  • LR(RL)两种
  • 上溢(四种)Uncle是红色
  • 添加代码
  • 删除
  • 删除——red节点
  • 删除——black节点(3情况)
  • 删除——拥有一个red节点的black节点
  • 删除——black叶子节点,sibling为black(方法是借兄弟)
  • 删除——black叶子节点,sibling为black(兄弟借不了,父节点下来合并)
  • 删除——black叶子节点,sibling为red(借兄弟的孩子)
  • 删除代码


代码框架

import java.util.Comparator;

public class RBTree<E> extends BinarySearchTree<E>{
	private static final boolean RED = false;
	private static final boolean BLACK = true;
	
	public RBTree() {
		this(null);
	}
	public RBTree(Comparator<E> comparator) {
		super(comparator);
	}
	
	/**
	 * 红黑树的节点类
	 * 节点有颜色,RED 或者 BLACK
	 *默认新添加为红色
	 */
	private static class RBNode<E> extends Node<E> {
		boolean color = RED;
		public RBNode(E element, Node<E> parent) {
			super(element, parent);
		}
		
		@Override
		public String toString() {
			String str = "";
			if (color == RED) {
				str = "R_";
			}
			return str + element.toString();
		}
	}
	
	@Override
	protected void afterAdd(Node<E> node) {
		
	}
	
	@Override
	protected void afterRemove(Node<E> node) {
		
	}

}

添加(12种情况)

nginx红黑树使用 红黑树代码_ide


添加的所有情况

17左右,33左右,46左,50左右,72左右,76右,88左右,一共12种

nginx红黑树使用 红黑树代码_ide_02

在黑节点后+节点,满足红黑树的性质;而在红色叶子节点后+节点,不满足红黑树性质
以下是修复的方法

修复性质4(添加在父节点为红色的情况)

LL(RR)两种

在祖父节点的右孩子的右边添加或在祖父节点的左孩子的左边添加。

若新添加的元素的叔父节点不是红色的情况

nginx红黑树使用 红黑树代码_父节点_03

LR(RL)两种

nginx红黑树使用 红黑树代码_nginx红黑树使用_04

上溢(四种)Uncle是红色

粉红色为新增加的节点

(LL)

nginx红黑树使用 红黑树代码_父节点_05


(RR)

nginx红黑树使用 红黑树代码_nginx红黑树使用_06


(LR)

nginx红黑树使用 红黑树代码_子节点_07


(RL)

nginx红黑树使用 红黑树代码_子节点_08

添加代码

@Override
protected void afterAdd(Node<E> node) {
	Node<E> parent = node.parent;
	
	// 添加的是根节点 或者 上溢到达了根节点
	if (parent == null) {
		black(node);//把根节点变黑
		return;
	}
	
	// 如果父节点是黑色,直接返回
	if (isBlack(parent)) return;
	
	// 叔父节点
	Node<E> uncle = parent.sibling();
	// 祖父节点
	Node<E> grand = red(parent.parent);
	
	if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】
		black(parent);
		black(uncle);
		// 把祖父节点当做是新添加的节点
		afterAdd(red(grand));
		return;
	}
	
	// 叔父节点不是红色
	if (parent.isLeftChild()) { // L
		if (node.isLeftChild()) { // LL
			black(parent);
			red(grand);
			rotateRight(grand);
		} else { // LR
			black(node);
			red(grand);
			rotateLeft(parent);
			rotateRight(grand);
		}
		rotateRight(grand);
	} else { // R
		if (node.isLeftChild()) { // RL
			black(node);
			red(grand);
			rotateRight(parent);
			rotateLeft(grand);
		} else { // RR
			black(parent);
			red(grand);
			rotateLeft(grand);
		}
	}
}

删除

nginx红黑树使用 红黑树代码_子节点_09

删除——red节点

nginx红黑树使用 红黑树代码_ide_10

删除——black节点(3情况)

nginx红黑树使用 红黑树代码_子节点_11

删除——拥有一个red节点的black节点

应该通过节点颜色判断,而不是用二叉搜索树里度为几的概念来判断

nginx红黑树使用 红黑树代码_nginx红黑树使用_12


nginx红黑树使用 红黑树代码_父节点_13

删除——black叶子节点,sibling为black(方法是借兄弟)

B树要求父节点的元素个数比它子节点的个数少1,如图,要删除88,就会出现下溢的情况

76是88的兄弟

nginx红黑树使用 红黑树代码_子节点_14


第三个选择了LL,只旋转一次,如果LR的需要旋转两次

nginx红黑树使用 红黑树代码_nginx红黑树使用_15

删除——black叶子节点,sibling为black(兄弟借不了,父节点下来合并)

如果删除节点的父节点为红,那么她边上定有合并的黑色节点,它下来合并,原来的节点就不会发生下溢。

如果删除节点的父节点为黑,下来的话上面就会发生下溢

不肯能存在父节点为黑,她边上定有合并的红色节点,因为条件就是被删除元素的兄弟节点为黑

nginx红黑树使用 红黑树代码_父节点_16

删除——black叶子节点,sibling为red(借兄弟的孩子)

将兄弟孩子变成兄弟,这样就可以套用上面的方法(当兄弟是黑色节点时就借兄弟)

让80右旋转

nginx红黑树使用 红黑树代码_子节点_17

删除代码