首先说一下红黑树的五个性质:
1、每个结点要么是红色的,要么是黑色的;
2、根结点是黑色的;
3、每个叶结点,即空结点(NIL)是黑色的;
4、如果一个结点是红色的,那么它的两个子结点都是黑色的;
5、对每个结点,从该结点到其子结点的所有路径上包含相同数目的黑结点。
在对红黑树插入的时候,我们一般都会插入红色的结点,红黑树的插入主要有这几种情况:
1、插入的是根结点;
此时,只会违反性质2,那么直接把此结点涂为黑色即可。
2、插入的结点的父节点是黑色的;
此时什么都不需要做。
3、插入的结点的父节点是红色且叔父结点是红色;
此时又分为几种情况:
1)、父节点是祖父结点的左子树还是右子树;
2)、插入的结点是父节点的左子树还是右子树。
无论哪种情况,解决策略都是:
对插入的结点(当前结点)的父节点和叔父结点涂黑,祖父结点涂红,把当前结点指向祖父结点,递归执行第1种情况。
4、插入的结点的父节点是红色,叔父结点是黑色的。
这种情况又分为以下几种情况:
1)、插入结点为父结点的左结点,父节点为祖父结点的左结点;
解决方案:父节点变黑,祖父结点变红,然后以祖父结点为支点右旋。
2)、插入结点为父节点的右节点,父节点为祖父结点的左结点;
解决方案:以当前结点的父节点为支点左旋,然后再以当前结点的左结点执行第1)种情况。
3)、插入结点为父节点的左结点,父节点为祖父结点的右节点;
解决方案:以当前结点的父节点为支点右旋,然后再以当前结点的右节点执行第4)中情况。
4)、插入结点为父节点的右节点,父节点为祖父结点的右节点。
解决方案:父节点变黑,祖父结点变红,然后以祖父结点为支点左旋。
代码实现如下:
package com.tyxh.rab;
public class TreeNode {
public int data;
public TreeNode lchild;
public TreeNode rchild;
public TreeNode parent;
public boolean color;
public TreeNode( int data, TreeNode lchild, TreeNode rchild,
TreeNode parent, boolean color) {
this. data = data;
this. lchild = lchild;
this. rchild = rchild;
this. parent = parent;
this. color = color;
}
}
package com.tyxh.rab;
public class BTTree {
public static final boolean RED = false;
public static final boolean BLACK = true;
private TreeNode root;
public BTTree() {
root = null;
}
public TreeNode grandParentNode(TreeNode node) {
// 获得祖父节点
return node. parent. parent;
}
public TreeNode uncleParentNode(TreeNode node) {
// 获得叔父节点
if (node. parent == grandParentNode(node). lchild)
return grandParentNode(node). rchild;
else
return grandParentNode(node). lchild;
}
// 左旋
private void singRotateLeft(TreeNode k2) {
TreeNode k1 = k2. rchild;
k2. rchild = k1. lchild;
k1. lchild = k2;
}
// 右旋
private void singRotateRight(TreeNode k2) {
TreeNode k1 = k2. lchild;
k2. lchild = k1. rchild;
k1. rchild = k2;
}
// 插入
// 1、新结点位于树的根上,没有父节点
public void insert_case1(TreeNode node) {
if (node. parent == null)
node. color = BLACK;
else
insert_case2(node);
}
// 2、新节点的父节点是黑色的
public void insert_case2(TreeNode node) {
if (node. parent. color == BLACK)
return;
else
insert_case3(node);
}
// 3、父节点是红色的,叔父节点也是红色的
public void insert_case3(TreeNode node) {
if (uncleParentNode(node) != null && uncleParentNode(node).color == RED ) {
node. parent. color = BLACK;
uncleParentNode(node). color = BLACK;
grandParentNode(node). color = RED;
insert_case1(grandParentNode(node));
} else
insert_case4(node);
}
// 4、父节点是红色的,叔父结点是黑色的或者为Nil,并且插入结点是父节点的右节点,父节点是祖父结点的左结点
public void insert_case4(TreeNode node) {
if (node == node. parent. rchild
&& node. parent == grandParentNode(node).lchild) {
// 以node.parent为结点左旋
singRotateLeft(node. parent);
node = node. lchild;
} else if (node == node. parent. lchild
&& node. parent == grandParentNode(node).rchild) {
// 以node.parent为结点右旋
singRotateRight(node. parent);
node = node. rchild;
}
insert_case5(node);
}
// 5、父亲结点是红色的,叔父是黑色的或者为Nil,并且插入结点是父节点的左结点,父节点是祖父结点的左结点
public void insert_case5(TreeNode node) {
node. parent. color = BLACK;
grandParentNode(node). color = RED;
if (node == node. parent. lchild
&& node. parent == grandParentNode(node).lchild) {
// 以祖父结点为结点右旋
singRotateRight(grandParentNode(node));
} else if (node == node. parent. rchild
&& node. parent == grandParentNode(node).rchild) {
// 以祖父结点为结点左旋
singRotateLeft(grandParentNode(node));
}
}
// 中序遍历
public void traversal() {
insubtree( root);
}
private void insubtree(TreeNode node) {
if (node == null)
return;
insubtree(node. lchild);
System. out.println(node. data + "、");
insubtree(node. rchild);
}
}