手写红黑树

红黑树(二)

一.插入

插入的所有结点默认是红色。插入结点称为默认结点

1.变色:

条件:父亲结点是红色,叔叔结点是红色
操作:
(1)父亲结点变成黑色。
(2)叔叔结点变成黑色。
(3)爷爷结点变成红色。
(4)当前结点设为爷爷。

2.旋转

条件:当前父结点是红色,叔叔是黑色,当前结点是右子树。
操作:以父结点左旋,当前结点设为父结点。

条件:当前父结点是红色,叔叔是黑色,当前结点是左字数。
操作:
(1)父亲结点变成黑色
(2)把爷爷结点变成红色
(3)以爷爷结点右旋

3.代码

首先来颗红黑树:
在这里插入图片描述
假设我们需要插入一个元素:值是19。
在这里插入图片描述
这时候就不满足红黑树的一些性质了,出现两个连在一起的红结点。需要进行一些变色和旋转操作。

首先:创建一个结点类。
并将上一篇帖子写的左旋和右旋操作对应的方法放入结点类中。
原文链接:https://blog.csdn.net/leno_scholar/article/details/106426806

public class Node {
    private final int Red = 0;
	private final int Black =1;
	
	public int data;          //存的数字
	int color = Red;          //颜色
	
	Node left;                //左子树
	Node right;               //右字数
	Node parent;              //父节点

    //左旋
    //以形参node做为根旋转。
	public void leftRotate(Node node){
		if(node.parent == null){
			Node A = node;     //根节点
			Node B = A.right;  //根节点的右节点
			
			//移动三部曲:动B的左节点
			//第一步
			B.left.parent = A;
			
			//第二部:动B节点
			B.left = A;
			B.parent = null;
			
			//三部曲:动A节点
			A.parent = B;
			A.right = B.left;
		}
	}
	
	
	//右旋
	//以形参node做为根旋转。
	public void rightRotate(Node node){
		if(node.parent == null){
			Node A = node;
			Node S = node.left;
			
			//移动三部曲:动B的右节点
			//一部曲
			B.right.parent = A;
			
			//二部曲:动B节点
			B.right = A;
			B.parent = null;
			
			//三部曲:动A节点
			A.parent = B;
			A.left = B.right;
		}
	}
}

为了便于区分,将插入方法单独展示(插入方法仍放与Node类中):
这个方法就是对中序二叉树的插入方法。多个判断是否达成红黑树性质。

/*
将这棵树的根结点作为参数传入,value是需要插入的值。
当然,这个value可以是对象、引用,甚至可以是另一棵红黑树(有点3D红黑树的味道)。
*/
public void inser(Node root,int data){
		if(root.data < data){
			if(root.right == null){
				root.right = new Node(data);
				isRedAndBlackTree(root.right);    //判断插入后这颗红黑树是否平衡
			}else{
				inser(root.right, data);
			}
		}else{
			if(root.left == null){
				root.left = new Node(data);
				isRedAndBlackTree(root.left);    //判断插入后这颗红黑树是否平衡
			}else{
				inser(root.left, data);
			}
		}
	}

接下来单独写这个isRedAndBlackTree()方法,这也是重点。

public void isRedAndBlackTree(Node node){
		Node grandParent = node.parent.parent;    //找到当前结点的爷爷结点。

        //下面开始判断是否需要变色。红0,黑1
		if( (grandParent.left.color == 0) && (grandParent.right.color == 0) ){
		
			//叔叔和父亲一起变黑。
			grandParent.left.color = Black;    
			grandParent.right.color = Black;
			
			//爷爷变红
			grandParent.color = Black;
		}
		node = grandParent;//把爷爷节点设为当前节点。
		
		grandParent = node.parent.parent;    //刷新爷爷(自己变成了爷爷,需要新爷爷)
		Node uncle;                          //找叔叔()
		if(grandParent.left == node.parent){    //如果爷爷的左孩子是自己的爸爸,那叔叔就是爷爷的右孩子
			uncle = grandParent.right;
		}else
			uncle = grandParent.left;           //反之,取反。
		
		//开始判断是否需要旋转
		if( (uncle.color == 1) && (node.parent.color == 0)){
			if(node == node.parent.right){  //如果是右子树
				leftRotate(node.parent);    //左旋
				node = node.left;     //更新当前结点,当前结点设为旋转的根结点。
				
				//接着右旋爷爷节点
				grandParent = node.parent.parent;  //更新爷爷
				if(grandParent.left == node.parent){  /更新叔叔
					uncle = grandParent.right;
				}else
					uncle = grandParent.left;
				
				//开始判断是否需要二次旋转。
				if(node.parent.color == 0 && uncle.color == 1){
					node.parent.color = Black;
					grandParent.color = Red;
					rightRotate(grandParent);
				}
				
			}else{                          //如果是左子树,右旋
				node.parent.color = Black;       //右旋比左旋多两步。
				node.parent.parent.color = Black;
				rightRotate(node.parent.parent); 
				node = node.parent.right;        //将当前结点设为旋转的根结点
				
				//更新爷爷和叔叔
				grandParent = node.parent.parent;
				if(grandParent.left == node.parent){
					uncle = grandParent.right;
				}else
					uncle = grandParent.left;
				
				//判断是否需要二次旋转。
				if(node.parent.color == 0 && uncle.color == 1){
					node.parent.color = Black;
					grandParent.color = Red;
					leftRotate(grandParent);
				}
			}
		}
	}

欢迎大佬纠正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值