插入与Java代码实现-红黑树-数据结构和算法
目录
内容
1、前期分析
-
红黑树插入节点过程大致分析:
- RBTree为二叉搜索树,我们按照二叉搜索树的方法对其进行节点插入
- RBTree有颜色约束性质,因此我们在插入新节点之后要进行颜色调整
-
新节点颜色调整
当红黑树插入新节点后,有可能破坏红黑树的特性,变成一棵普通的树。这时候我需要进行调整,为了尽可能的减少工作量, 我们通过观察发现其中,红黑树的前3条特性是不会违反的;为了符合第5条特性,我们一般把新节点的颜色设置为红色;那么剩下就只可能是违反第4条规定,既从每个叶子到根的所有路径上不能有两个连续的红色结点。我们接下来的调整,只需要关注这点就可以了。
2、插入步骤
根据给定信息,创建新节点,颜色为红色。
2.1、红黑树为空
- 根节点root指向该节点,节点颜色设置黑色
2.2、按照二叉搜索树的方法对其进行节点插入
2.3、对红黑树进行平衡调整
3、平衡性调整
-
获取目标节点x的父节点xp,如何xp为空,说明x为根节点,把节点x颜色设置为黑色(性质2)调整结束
-
如果xp节点颜色为黑色或者获取xp的父节点xpp,如果xpp为空,调整结束
-
如何不符合情况1,2,那么现在条件 xp非空红色,xpp非空。xp可能是xpp的左节点或者右节点,我们以左节点为例。
-
xp为xpp的左节点,如果xpp的右节点xppr不为空且颜色为红色,那么xpp一定为黑色(性质4)
- 那么节点xp,xppr 颜色设置为黑色
- xpp设置为红色
- 把xpp赋值给当前节点x
- 图示:
- 目标就是把红色节点网根节点方向转移
-
xp为xpp的左节点,且不满足条件4
-
如果x为xp的右节点,那么通过节点xp左旋,xp设置为当前节点x,以满足下面条件5.2
- 图示:
-
此时如果xp不为空,xp颜色设置为黑色,如何xpp也不为空,xpp颜色设置为红色,对节点xpp右旋
- 图示:
-
-
xp为xpp的右节点同理,这里不再详述
-
重复以上步骤,知道满足条件1或者2退出循环
4、Java代码实现
- 插入代码
// 插入
public V add(K k, V v) {
if (k == null) return null;
RBNode<K, V> n = new RBNode<>(k, v, true, null, null, null);
if (root == null) {
n.red = false;
root = n;
size = 1;
return v;
}
RBNode<K, V> pp = null;
RBNode<K, V> p = root;
while (p != null) {
if (((Comparable) k).compareTo(p.key) < 0) {
pp = p;
p = p.left;
} else if (((Comparable) k).compareTo(p.key) > 0) {
pp = p;
p = p.right;
} else {
V value = p.value;
p.value = v;
return value;
}
}
n.parent = pp;
if (((Comparable) k).compareTo(pp.key) < 0)
pp.left = n;
else
pp.right = n;
root = balanceInsertion(root, n);
size++;
return v;
}
- 插入后平衡性调整代码
// 插入后平衡调整
static <K, V> RBNode<K, V> balanceInsertion(RBNode<K, V> root, RBNode<K, V> x) {
x.red = true;
for (RBNode<K, V> xp, xpp, xppl, xppr; ; ) {
if ((xp = x.parent) == null) {
x.red = false;
return x;
} else if (!xp.red || (xpp = xp.parent) == null)
return root;
if (xp == (xppl = xpp.left)) {
if ((xppr = xpp.right) != null && xppr.red) {
xp.red = xppr.red = false;
xpp.red = true;
x = xpp;
} else {
if (x == xp.right) {
root = rotateLeft(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateRight(root, xpp);
}
}
}
} else {
if (xppl != null && xppl.red) {
xppl.red = xp.red = false;
xpp.red = true;
x = xpp;
} else {
if (x == xp.left) {
root = rotateRight(root, x = xp);
xpp = (xp = x.parent) == null ? null : xp.parent;
}
if (xp != null) {
xp.red = false;
if (xpp != null) {
xpp.red = true;
root = rotateLeft(root, xpp);
}
}
}
}
}
}
5、测试及打印
- 测试代码:
public static void testRBTree() {
RBTree<Integer, String> rbTree = new RBTree<>();
rbTree.add(1, "aaa");
rbTree.add(23, "sdf");
rbTree.add(63, "434");
rbTree.add(634, "r4f");
rbTree.add(223, "2342");
rbTree.add(22, "fwff");
System.out.println(rbTree);
System.out.println(rbTree.size());
// rbTree.removeRBTreeNode(63);
// System.out.println(rbTree);
// System.out.println(rbTree.size());
}
// 打印结果
[(1,aaa,黑),(22,fwff,红),(23,sdf,黑),(63,434,红),(223,2342,黑),(634,r4f,红)]
6
- 参考地址
- Jdk HashMap TreeNode
- 浅析红黑树(RBTree)原理及实现
后记 :
欢迎交流,本人QQ:806797785
项目源代码地址:https://gitee.com/gaogzhen/algorithm.git