操作术语
红黑树节点主要成员包括指向左孩子、右孩子、父节点的引用,一个boolean类型的变量标识是红或黑。
对于查询操作,跟二叉搜索树一样
插入、删除可能会影响红黑树的平衡,需要通过旋转和变色维护。
左旋逻辑:
设对节点p左旋,其目标为使节点p成为其右孩子节点的左孩子节点,操作为修改节点p和节点p的右孩子节点的父指针,再修改各自的孩子指针。
右旋逻辑:
设对节点p右旋,其目标为使节点p成为其左孩子节点的右孩子节点,操作为修改节点p和节点p的左孩子节点的父指针,再修改各自的孩子指针。
插入逻辑:
- 找插入位置,要插入的节点肯定为叶子节点,且设置为红色
- 判断其父节点颜色而做相应旋转以及变色操作
删除逻辑:
- 要删除的节点有左孩子节点和右孩子节点,找其直接后继节点,交换位置,待替换的节点指向后继节点的右孩子节点(如果存在的话,否则指向自己)
- 要删除的节点孩子节点仅有一个,替换节点即为其孩子节点
- 要删除的节点没有孩子节点,替换节点指向自己
- 如果替换节点不为删除节点,则将替换节点直接替换删除节点
- 根据删除节点颜色,做平衡操作
- 替换节点就是删除节点,修改指针引用,将其删除
图文并茂请参考https://blog.csdn.net/weixin_45685353/article/details/105912742?spm=1001.2014.3001.5502
代码实现
import java.util.*;
/**
* 文件描述
*
* @author bipa
* @date 2022/7/5
*/
public class RedBlackTree<T> {
private TreeNode root;
private Comparator<? super T> comparator;
public RedBlackTree() {
}
public RedBlackTree(Comparator<? super T> comparator) {
this.comparator = comparator;
}
class TreeNode {
private T val;
private TreeNode left;
private TreeNode right;
private TreeNode parent;
private boolean red;
public TreeNode(T val) {
this.val = val;
}
}
public TreeNode find(T target) {
TreeNode p = root;
for (; p != null; ) {
int dir = comparator == null ? ((Comparable<? super T>) target).compareTo(p.val) : comparator.compare(target, p.val);
if (dir < 0) {
p = p.left;
} else if (dir > 0) {
p = p.right;
} else {
return p;
}
}
return null;
}
public void insert(T val) {
TreeNode p = root, pp = null;
int dir = 0;
for (; p != null; ) {
pp = p;
dir = comparator == null ? ((Comparable<? super T>) val).compareTo(p.val) : comparator.compare(val, p.val);
if (dir < 0) {
p = p.left;
} else if (dir > 0) {
p = p.right;
} else {
return;
}
}
TreeNode node = new TreeNode(val);
if (pp == null) {
node.red = false;
root = node;
return;
}
if (dir < 0) {
pp.left = node;
} else {
pp.right = node;
}
node.parent = pp;
balanceInsert(node);
}
public List<T> getInnerValues() {
List<T> list = new ArrayList<>();
ArrayDeque<TreeNode> stack = new ArrayDeque<>();
TreeNode p = root;
while (p != null || !stack.isEmpty()) {
while (p != null) {
stack.addLast(p);
p = p.left;
}
p = stack.removeLast();
list.add(p.val);
p = p.right;
}
return list;
}
public void remove(T target) {
TreeNode t;
if ((t = this.find(target)) == null) {
return;
}
if (t == root && t.left == null && t.right == null) {
root = null;
return;
}
TreeNode tl = t.left, tr = t.right, replace;
if (tl != null && tr != null) {
TreeNode s = tr, sl;
while ((sl = s.left) != null) {
s = sl;
}
boolean c = t.red;
t.red = s.red;
s.red = c;
TreeNode sr = s.right, tp = t.parent;
if (tr == s) {
t.parent = s;
s.right = t;
} else {
TreeNode sp = s.parent;
if ((t.parent = sp) != null) {
if (s == sp.left) {
sp.left = t;
} else {
sp.right = t;
}
}
s.right = tr;
tr.parent = s;
}
t.left = null;
if ((t.right = sr) != null) {
sr.parent = t;
}
s.left = tl;
tl.parent = s;
if ((s.parent = tp) == null){
root = s;
} else if (t == tp.left) {
tp.left = s;
} else {
tp.right = s;
}
if (sr != null) {
replace = sr;
} else {
replace = t;
}
} else if (tl != null) {
replace = tl;
} else if (tr != null) {
replace = tr;
} else {
replace = t;
}
if (replace != t) {
TreeNode tp = replace.parent = t.parent;
if (tp == null) {
root = replace;
} else if (tp.left == t) {
tp.left = replace;
} else {
tp.right = replace;
}
t.left = t.right = t.parent = null;
}
if (!t.red) {
balanceRemove(replace);
}
if (replace == t) {
TreeNode tp = t.parent;
t.parent = null;
if (tp != null) {
if (tp.left == t) {
tp.left = null;
} else {
tp.right = null;
}
}
}
}
private void balanceInsert(TreeNode t) {
TreeNode tp, tpp, tppl, tppr;
t.red = true;
for (; ; ) {
if ((tp = t.parent) == null) {
t.red = false;
return;
}
if (!tp.red || (tpp = tp.parent) == null) {
return;
}
if ((tppl = tpp.left) == tp) {
if ((tppr = tpp.right) != null && tppr.red) {
tppl.red = false;
tppr.red = false;
tpp.red = true;
t = tpp;
} else {
if (t == tp.right) {
rotateLeft(t = tp);
tpp = (tp = t.parent) == null ? null : tp.parent;
}
if (tp != null) {
tp.red = false;
if (tpp != null) {
tpp.red = true;
rotateRight(tpp);
}
}
}
} else {
if (tppl != null && tppl.red) {
tppl.red = false;
tp.red = false;
tpp.red = true;
t = tpp;
} else {
if (t == tp.left) {
rotateRight(t = tp);
tpp = (tp = t.parent) == null ? null : tp.parent;
}
if (tp != null) {
tp.red = false;
if (tpp != null) {
tpp.red = true;
rotateLeft(tpp);
}
}
}
}
}
}
private void balanceRemove(TreeNode t) {
TreeNode tp, tpl, tpr;
for (; ; ) {
if (t == null || t == root) {
return;
} else if ((tp = t.parent) == null) {
t.red = false;
return;
} else if (t.red) {
t.red = false;
return;
} else if ((tpl = tp.left) == t) {
if ((tpr = tp.right) != null && tpr.red) {
tpr.red = false;
tp.red = true;
rotateLeft(tp);
tpr = (tp = t.parent) == null ? null : tp.right;
}
if (tpr == null) {
t = tp;
} else {
TreeNode sl = tpr.left, sr = tpr.right;
if ((sr == null || !sr.red) && (sl == null || !sl.red)) {
tpr.red = true;
t = tp;
} else {
if (sr == null || !sr.red) {
sl.red = false;
tpr.red = true;
rotateRight(tpr);
tpr = (tp = t.parent) == null ? null : tp.right;
}
if (tpr != null) {
tpr.red = tp != null && tp.red;
if ((sr = tpr.right) != null) {
sr.red = false;
}
}
if (tp != null) {
tp.red = false;
rotateLeft(tp);
}
t = root;
}
}
} else {
if (tpl != null && tpl.red) {
tpl.red = false;
tp.red = true;
rotateRight(tp);
tpl = (tp = t.parent) == null ? null : tp.left;
}
if (tpl == null) {
t = tp;
} else {
TreeNode sl = tpl.left, sr = tpl.right;
if ((sl == null || !sl.red) && (sr == null || !sr.red)) {
tpl.red = true;
t = tp;
} else {
if (sl == null || !sl.red) {
sr.red = false;
tpl.red = true;
rotateLeft(tpl);
tpl = (tp = t.parent) == null ? null : tp.left;
}
if (tpl != null) {
tpl.red = tp != null && tp.red;
if ((sl = tpl.left) != null) {
sl.red = false;
}
}
if (tp != null) {
tp.red = false;
rotateRight(tp);
}
t = root;
}
}
}
}
}
private void rotateLeft(TreeNode t) {
TreeNode tr, trl, tp;
// 左旋,成为其右子节点的左子节点
if (t != null && (tr = t.right) != null) {
// 修改父指针
if ((tp = tr.parent = t.parent) == null) {
tr.red = false;
root = tr;
} else if (tp.left == t) {
tp.left = tr;
} else {
tp.right = tr;
}
// 修改子指针
if ((trl = t.right = tr.left) != null) {
trl.parent = t;
}
// 成为其右子节点的左子节点
tr.left = t;
t.parent = tr;
}
}
private void rotateRight(TreeNode t) {
TreeNode tl, tlr, tp;
// 右旋,成为其左子节点的右子节点
if (t != null && (tl = t.left) != null) {
// 修改父指针
if ((tp = tl.parent = t.parent) == null) {
tl.red = false;
root = tl;
} else if (tp.left == t) {
tp.left = tl;
} else {
tp.right = tl;
}
// 修改子指针
if ((tlr = t.left = tl.right) != null) {
tlr.parent = t;
}
// 成为其左子节点的右子节点
tl.right = t;
t.parent = tl;
}
}
}
测试验证
测试类如下,
import com.bipa.tree.RedBlackTree;
import java.util.List;
/**
* 文件描述
*
* @author bipa
* @date 2022/7/5
*/
public class Main {
public static final int LOOP_NUM = 10_000;
public static void main(String[] args) {
RedBlackTree<Integer> redBlackTree = new RedBlackTree<>();
for (int i = LOOP_NUM; i > 0; i--) {
redBlackTree.insert(i);
}
for (int i = LOOP_NUM; i > 0; i--) {
// 获取红黑树中序遍历后的节点值
List<Integer> list = redBlackTree.getInnerValues();
System.out.println(list);
// 验证是否升序
for (int j = 1; j < list.size(); j++) {
if (list.get(j-1) > list.get(j)) {
// 发现降序,打印fail,结束方法
System.out.println("fail!");
return;
}
}
redBlackTree.remove(i);
}
System.out.println("succ");
}
}
运行结果截图,