1,介绍
红黑树是一种自平衡的二叉搜索树,它可以保证在最坏情况下的基本操作的时间复杂度为 O(log n)。它被广泛应用于数据库、编译器和其他软件系统中。在本文中,我们将学习如何在 Java 中实现红黑树。我们将创建一个节点类和一个树类,实现插入方法和平衡方法。
类定义及常量
public class Hhs<Key extends Comparable<Key>, Value> {
private static final boolean RED = true;
private static final boolean BLACK = false;
Hhs 类接受两个泛型参数:Key 和 Value,其中 Key 需要实现 Comparable 接口,以便支持键的比较操作。
定义了两个静态常量 RED 和 BLACK 来表示红黑树中节点的颜色。
内部类 Node
private class Node {
Key key;
Value value;
Node left, right;
int N;
boolean color;
Node 是 Hhs 类的内部类,用于表示红黑树中的每个节点。
每个节点包含键 key、值 value、指向左右子节点的指针 left 和 right、节点的子树大小 N 和颜色 color。
核心方法
public int size() {
return size(root);
}
private int size(Node x) {
if (x == null) return 0;
return x.N;
}
size() 方法返回树中节点的总数,通过递归调用私有的 size(Node x) 实现。
isRed()
private boolean isRed(Node x) {
if (x == null) return false;
return x.color == RED;
}
isRed() 方法检查给定节点的颜色是否为红色。
rotateLeft() 和 rotateRight()
Node rotateLeft(Node a);
Node rotateRight(Node a);
这两个方法分别实现左旋和右旋操作,用于调整树的结构以保持红黑树的性质。
左旋和右旋操作涉及节点之间的链接调整和颜色更新,以确保旋转后的树仍然满足红黑树的规则。
flipColors()
void flipColors(Node a);
flipColors() 方法用于翻转节点及其子节点的颜色,通常在插入操作后调用,以恢复红黑树的性质。
put()
public void put(Key key, Value value);
put() 方法用于向红黑树中插入新的键值对。
它首先调用私有的 put(Node a, Key key, Value value) 方法来递归地查找插入位置,并在必要时进行旋转和颜色翻转操作。
插入操作结束后,根节点的颜色会被强制设置为黑色,以满足红黑树的根节点颜色规则。
完整代码
public class Hhs <Key extends Comparable<Key>,Value> {
private static final boolean red = true;
public static final boolean black = false;
private Node root;
private class Node{
Key key;
Value value;
Node left,right;
int N;
boolean color;
public Node(Key key, Value value, int n, boolean color) {
this.key = key;
this.value = value;
N = n;
this.color = color;
}
}
public int size() {
return size(root);
}
private int size(Node x) {
if (x == null) return 0;
return x.N;
}
private boolean isRed(Node x){
if(x == null) return false;
return x.color = red;
}
Node rotateLeft(Node a){
Node x = a.right;
a.right = x.left;
x.left = a;
x.color = a.color;
a.color = red;
x.N = a.N;
a.N = 1 + size(a.left) + size(a.right);
return x;
}
Node rotateRight(Node a) {
Node x = a.left;
a.left = x.right;
x.right = a;
x.color = a.color;
a.color = red;
x.N = a.N;
a.N = 1 + size(a.left) + size(a.right);
return x;
}
void flipColors(Node a) {
a.color = red;
a.left.color = black;
a.right.color = black;
}
public void put(Key key, Value value) {
root = put(root, key, value);
root.color = black;
}
private Node put(Node a, Key key, Value value) {
if (a == null) return new Node(key, value, 1, red);
int cmp = key.compareTo(a.key);
if (cmp < 0) a.left = put(a.left, key, value);
else if (cmp > 0) a.right = put(a.right, key, value);
else a.value = value;
if (isRed(a.right) && !isRed(a.left)) a = rotateLeft(a);
if (isRed(a.left) && isRed(a.left.left)) a = rotateRight(a);
if (isRed(a.left) && isRed(a.right)) flipColors(a);
a.N = size(a.left) + size(a.right) + 1;
return a;
}
}