1、基本特征
红黑树起源于2-3-4树(或2-3树),底层是二叉查找树,除二叉树的特性外,还有5大特性:
-
根是黑色
-
节点是黑色或红色
-
叶子节点都是黑色
叶子节点为NIL节点,不可忽略,见下图
-
每个红色节点的两个子节点必须是黑色
从每个叶子到根的路径上不能有两个连续的红节点
-
黑色平衡
从任一节点到其所有叶子节点的简单路径上黑色节点数量相同
2、内部节点类Node
双向链表:父 > 子 子 > 父
/**
* 内部节点类
*/
private class Node {
/**
* 键 key
*/
private K key;
/**
* 值 value
*/
private V value;
/**
* 父节点
*/
private Node parent;
/**
* 左子节点
*/
private Node left;
/**
* 右子节点
*/
private Node right;
/**
* 节点颜色
* 红色:true
* 黑色:false
*/
private boolean color;
/**
* 构造器
*
* @param key
* @param value
* @param parent
* @param left
* @param right
*/
public Node(K key, V value, Node parent, Node left, Node right) {
this.key = key;
this.value = value;
this.parent = parent;
this.left = left;
this.right = right;
this.color = BLACK;
}
}
3、成员变量与构造器
/**
* @author 土味儿
* Date 2021/9/10
* @version 1.0
* 红黑树
*/
public class RedBlackTree1<K extends Comparable<K>, V> {
/**
* 根节点
*/
private Node root;
/**
* 元素数量
*/
private int n;
/**
* 红色
*/
private static final boolean RED = true;
/**
* 黑色
*/
private static final boolean BLACK = false;
/**
* 构造器
*/
public RedBlackTree1() {
this.n = 0;
}
}
4、基础方法
4.1、元素数量 size()
public
/**
* 元素数量
*
* @return
*/
public int size() {
return n;
}
4.2、节点颜色 colorOf()
private
/**
* 节点颜色
*
* @param x
* @return
*/
private boolean colorOf(Node x) {
if (x != null) {
return x.color == RED;
}
return BLACK;
}
5、查询
5.1、get()
public
/**
* 得到 key 结点的值
*
* @param key
* @return
*/
public V get(K key) {
Node node = getNode(key);
return node != null ? node.value : null;
}
5.2、getNode()
private
/**
* 获取 key 节点
*
* @param key
* @return
*/
private Node getNode(K key) {
// 空树、空键
if (root == null || key == null) {
return null;
}
// 从根结点开始查找
Node node = root;
// 比较 key 与 h 键的大小
int cmp;
// 循环遍历
while (node != null) {
cmp = key.compareTo(node.key);
if (cmp < 0) {
node = node.left;
} else if (cmp > 0) {
node = node.right;
} else {
return node;
}
}
return null;
}
5.3、树根
public
/**
* 得到树根的value
* @return
*/
public V getRoot(){
return root.value;
}
5.4、最小
-
getMin()
public
/**
* 最小值
* @return
*/
public V getMin() {
Node minNode = getMinNode();
return minNode != null ? minNode.value : null;
}
-
getMinNode()
private
/**
* 最小节点
* 最左侧叶子
*
* @return
*/
private Node getMinNode() {
Node p = root;
if (p != null) {
while (p.left != null) {
p = p.left;
}
}
return p;
}
5.5、最大
-
getMax()
public
/**
* 最大值
*
* @return
*/
public V getMax() {
Node maxNode = getMaxNode();
return maxNode != null ? maxNode.value : null;
}
-
getMaxNode()
private
/**
* 最大节点
* 最右侧叶子
*
* @return
*/
private Node getMaxNode() {
Node p = root;
if (p != null) {
while (p.right != null) {
p = p.right;
}
}
return p;
}
5.6、前驱节点
private
小于当前节点的最大节点
就是当前节点左子树中的最右节点;在左子树中循环向右,最后一个
/**
* 前驱节点
* 小于 t 的最大节点
* t 左子树中最右节点
*
* @param t
* @return
*/
private Node predecessor(Node t) {
// t 为null时,返回null
if (t == null) {
return null;
}
Node p;
// t 有左子树:在左子树中找出最右侧节点即可
if (t.left != null) {
p = t.left;<