一、题目
题目:红黑树插入算法 实验目的:实现有效的红黑树插入算法
二、算法思想
① 第一步和一般的搜索二叉树没什么区别。从树根开始搜索,如果插入值比节点大,就向右子树搜索,比节点小则向左子树搜索。直到走到叶节点位置,将插入值放在这个节点上。并标记它为红色。
② 之后,红黑树可能需要调整平衡。
对第4条性质的恢复,根据Z的父节点是Z的祖节点的左子节点还是右子节点,分为两组对称的情况,每组有3种情况。下面我们只对其中一组进行说明,以Z的父节点是Z祖节点的左子节点为例:
[第一种:Z的“叔父”节点是红色]:
在这种情况下,将父、叔节点都着为黑色,再将子树根节点着为红色,那么子树的黑高度没有发生改变,而且红黑性质得得到了调整。此时,再将Z指向子树的根节点,向上递归恢复红黑特性。
[第二种:Z的“叔父”节点是黑色的,Z是父节点的左子节点]
将Z的 父节点与祖节点进行一次右旋,并把父节点着黑色,原来的祖节点着红色。这些子树的红黑特性得到了恢复,而且子树的黑高度没有变化。另外,由于子树根节点已 经是黑色了(这个节点不会出现父子同为红色的问题了),所以不必再向上递归了,此时整个树的红黑特性都已经是正确的了。
[第三种:Z的“叔父”节点是黑色的,Z是父节点的右子节点]
将Z本身与其父节点进行一次左旋,让Z指向原来的父节点,就可以调整为情况二,而情况二已经得到解决。
这样,红黑树的节点插入问题就得到了解决。
三、实验结果
四、结果分析
实验结果的输入来自课堂作业的题目,经验证,结果正确,表明程序有效。
五、总结
l 红黑树是一种自平衡二叉查找树,典型的用途是实现关联数组。它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。
l 插入实际上是原地算法,因为上述所有调用都使用了尾部递归。
附件:
源程序:RBTreeExperiment.java
/**
* @author
* Email:
* 创建时间:2012-11-09 下午6:44:52
* 类说明 :红黑树插入算法
* @version
*/
public class RBTreeExperiment
{
public static void main(String args[]) {
RBTree rb = new RBTree();
RBTree.rb_insert(rb,new RBTreeNode(41));
RBTree.rb_insert(rb,new RBTreeNode(38));
RBTree.rb_insert(rb,new RBTreeNode(31));
RBTree.rb_insert(rb,new RBTreeNode(12));
RBTree.rb_insert(rb,new RBTreeNode(19));
RBTree.rb_insert(rb,new RBTreeNode(8));
System.out.println("依次插入值为41,38,31,12,19,8的节点后,中序遍历红黑树各节点:");
RBTree.inOrderTraverse(rb.root);
}
}
class RBTree{
public int number;
public RBTreeNode root;
public final static int RED=0;
public final static int BLACK=1;
public static void left_rotate(RBTree rb,RBTreeNode x) {//对x节点左旋转
if((rb==null) || (x==null))return;
//set y
RBTreeNode y = x.right;
//turn y's left subtree into x's right subtree
x.right = y.left;
if(y.left != null) {
y.left.p = x;
}
//link x's parent to y
y.p=x.p;
if(x.p == null) {
rb.root = y;
}
else if(x == x.p.left){
x.p.left=y;
}
else {
x.p.right=y;
}
//put x on y's left
y.left=x;
x.p=y;
}
public static void right_rotate(RBTree rb,RBTreeNode y) {//对y节点右旋转
if((rb==null) || (y==null))return;
//set x
RBTreeNode x = y.left;
//turn x's right subtree into y's left subtree
y.left=x.right;
if(x.right != null) {
x.right.p = y;
}
//link y's parent to x
x.p=y.p;
if(y.p == null) {
rb.root = x;
}
else if(y == y.p.left){
y.p.left=x;
}
else {
y.p.right=x;
}
//put y on x's right
x.right=y;
y.p=x;
}
public static void rb_insert(RBTree rb,RBTreeNode z){//在rb中插入z节点
if(z==null)return;
RBTreeNode y=null;
RBTreeNode x=rb.root;
while(x != null) {
y=x;
if(z.key < x.key) {
x=x.left;
}
else {
x=x.right;
}
}
z.p=y;
if(y == null) {
rb.root=z;
}
else if(z.key < y.key) {
y.left=z;
}
else {
y.right=z;
}
z.left=null;
z.right=null;
z.color=RED;
rb.number++;
rb_insert_fixup(rb,z);
}
public static void rb_insert_fixup(RBTree rb,RBTreeNode z) {//调整插入后的树
while((z.p != null) && (z.p.color == RED)){
if((z.p.p != null) && (z.p == z.p.p.left)) { //父亲节点是祖先节点的左孩子
RBTreeNode y=z.p.p.right;//uncle y
if((y != null) && (y.color==RED)) {
z.p.color=BLACK;
y.color=BLACK;
z.p.p.color=RED;
z=z.p.p;//important
}
else {
if(z==z.p.right) {
z=z.p;
left_rotate(rb,z);
}
z.p.color=BLACK;
z.p.p.color=RED;
right_rotate(rb,z.p.p);
}
}
else if(z.p.p != null){//父亲节点是祖先节点的右孩子
RBTreeNode y=z.p.p.left;//uncle y
if((y != null) && (y.color==RED)) {
z.p.color=BLACK;
y.color=BLACK;
z.p.p.color=RED;
z=z.p.p;//important
}
else {
if(z==z.p.left) {
z=z.p;
right_rotate(rb,z);
}
z.p.color=BLACK;
z.p.p.color=RED;
left_rotate(rb,z.p.p);
}
}
}
rb.root.color=BLACK;
}
public static void inOrderTraverse(RBTreeNode root) {
if(root==null)return;
inOrderTraverse(root.left);
if(root.color==RBTree.BLACK) {
System.out.println("black\t"+root.key);
}
else {
System.out.println("red\t"+root.key);
}
inOrderTraverse(root.right);
}
}
class RBTreeNode{
public RBTreeNode p;
public RBTreeNode left;
public RBTreeNode right;
public int key;
public int color;
public RBTreeNode() {} //提供无参构造器。以后可能会用到继承
public RBTreeNode(int key) {
this.key=key;
}
}