java--实现红黑树(二)

         一步一步来实现一下红黑树的删除:红黑树的删除分析

         首先,删除方法的入口,进行一定的条件判定:

/**  
	* delValue: delete the value from RBTree
	* @param value
	* @return 
	* boolean  返回类型   
	*/
	public boolean delValue(T value){
		if(this.root == null){
			throw new NullIsNotSupported("root is null");
		}
		if(!this.root.isBlack){
			throw new UnexpectedException("the tree is not a RBTree");
		}
		if(this.root.value == null || value == null){
			return false;
		}
		return delValue(this.root,value);
	}

 然后进入第二个方法:根据value值查询到节点t:

/**  
	* delValue: 从以root为根的rb树中删除value
	* @param root  
	* @param value
	* @return 
	* boolean  返回类型   
	*/
	public boolean delValue(RBNode<T> root,T value){
		TreeNode<T> t = this.searchNode(root,value);
		if(t == null){
			return false;
		}
		return this.delValue(root, (RBNode<T>)t);
	}

 然后进入第三个方法:找到t节点的后继(真正要删除的节点),更换节点t和后继节点的值:

/**  
	* delValue: 从以root为跟的RB树中删除节点t
	* @param root
	* @param t  RB节点t
	* @return 
	* boolean  返回类型   
	*/
	public boolean delValue(RBNode<T> root,RBNode<T> t){
		RBNode<T> delNode= getSubNode(t);
		swapValue(delNode,t,false);
		return this.delNode(delNode);
	}

/**  
	* getSubNode: 找到节点t的后继节点,供删除用
	* @param t
	* @return 
	* RBNode<T>  返回类型   
	*/
	private RBNode<T> getSubNode(RBNode<T> t){
		int leftDepth = TreeTools.getTreeDepth(t.left);
		int rightDepth = TreeTools.getTreeDepth(t.right);
		//如果右子树高,取右子树的最小节点
		if(leftDepth < rightDepth){
			t = getMinNode(t);
		}else{
			if(t.left.value != null){
				t = getMaxNode(t.left);
			}
		}
		return t;
	}
/**  
	* getMinNode: 获取最小节点
	* @param t
	* @return 
	* RBNode<T>  返回类型   
	*/
	private RBNode<T> getMinNode(RBNode<T> t){
		if(t.left.value != null){
			return getMinNode(t.left);
		}
		return t;
	}
	
	/**  
	* getMaxNode: 获得最大子节点
	* @param t
	* @return 
	* RBNode<T>  返回类型   
	*/
	private RBNode<T> getMaxNode(RBNode<T> t){
		if(t.right.value != null){
			return getMaxNode(t.right);
		}
		return t;
	}

 然后删除真正的节点:

/**  
	* delNode: 删除真正的节点t
	* @param t
	* @return 
	* boolean  返回类型   
	*/
	public boolean delNode(RBNode<T> t){
		//如果t是红色的或t就是根节点,直接删除t即可
		if(!t.isBlack || t.equals(this.root)){
			t = new RBNode<T>(t.father);
			return true;
		}else{
			//如果t是黑色的,并且有非空儿子,那么用非空儿子代替他,并且把非空儿子染成黑色即可
			if(t.left.value !=null){
				t = new RBNode<T>(t.father,t.left.value);
				t.setBlack();
			}else if(t.right.value != null){
				t = new RBNode<T>(t.father,t.right.value);
				t.setBlack();
			}else{
				//t没有非空儿子,那么删除t,然后调整整棵树
				t = new RBNode<T>(t.father);
				adjust(t);
			}
			return true;
		}
	}

 删除真正节点的时候,如果要删除的是红色节点,或者要删除的节点有红色儿子节点,那么不用进行调整,直接删除或者染相应的颜色即可。其他情况删除完后需要调整:

/**  
	* delNode: 删除真正的节点t
	* @param t
	* @return 
	* boolean  返回类型   
	*/
	public boolean delNode(RBNode<T> t){
		//如果t是红色的或t就是根节点,直接删除t即可
		if(!t.isBlack || t.equals(this.root)){
			t = new RBNode<T>(t.father);
			return true;
		}else{
			//如果t是黑色的,并且有非空儿子,那么用非空儿子代替他,并且把非空儿子染成黑色即可
			if(t.left.value !=null){
				t = new RBNode<T>(t.father,t.left.value);
				t.setBlack();
			}else if(t.right.value != null){
				t = new RBNode<T>(t.father,t.right.value);
				t.setBlack();
			}else{
				//t没有非空儿子,那么删除t,然后调整整棵树
				t = new RBNode<T>(t.father);
				adjust(t);
			}
			return true;
		}
	}

 调整方法:  后继节点的兄弟是红色的时候:

/**  
	* adjust: 以节点t为调整节点调整树,使它还变成红黑树
	* @param t 
	* void  返回类型   
	*/
	private void adjust(RBNode<T> t){
		//t节点是不是父节点的左孩子
		boolean isLeft = t.father.left.equals(t);
		if(isLeft){
			//如果t节点的兄弟是红色的
			if(!t.father.right.isBlack){
				//逆时针旋转到黑兄弟情况
				t = this.rotateWithRightChild(t.father.right).left;
			}
		}else{
			if(!t.father.left.isBlack){
				//顺时针旋转到黑兄弟情况
				t = this.rotateWithLeftChild(t.father.left).right;
			}
		}
		this.adjustForBlackBrother(t.right, isLeft);
	}

 当后继节点的兄弟是黑色:

/**  
	* adjustForBlackBrother: 以节点t为调整节点调整树,使它还变成红黑树(t的兄弟节点是黑色的)
	* @param t 
	* isLeft   t节点是否是父节点的左孩子
	* void  返回类型   
	*/
	private void adjustForBlackBrother(RBNode<T> t,boolean isLeft){
		//如果父节点是红色的
		if(!t.father.isBlack){
			t.father.setBlack();
			if(isLeft){
				t.father.right.setRed();
			}else{
				t.father.left.setRed();
			}
		}else{
			//首先,在这个条件下,t节点是黑色的,兄弟是黑色的,父节点是黑色的
			//如果t节点祖孙三代全黑色(兄弟黑色,兄弟的孩子都黑)
			if(isLeft && t.father.right.left.isBlack && t.father.right.right.isBlack){
				t.father.right.setRed();
				adjustForBlackBrother(t.father,isLeft);
			}else if(!isLeft && t.father.left.left.isBlack && t.father.left.right.isBlack){
				t.father.left.setRed();
				adjustForBlackBrother(t.father,isLeft);
			}else{//以下是当t是黑色的,兄弟是黑色的,父节点是黑色的,但是侄子节点有红色节点
				//t节点是左子树
				if(isLeft){
					//t节点的兄弟节点的右孩子是红色的
					if(!t.father.right.right.isBlack){
						t.father.right.right.setBlack();
						this.rotateWithRightChild(t.father.right);
					}else{
						t.father.right.left.setBlack();
						this.rotateWithLR(t.father.left);
					}
				}else{//t节点是右子树
					//t节点的兄弟节点的右孩子是红色的
					if(!t.father.left.right.isBlack){
						t.father.left.right.setBlack();
						this.rotateWithLeftChild(t.father.right);
					}else{
						t.father.left.left.setBlack();
						this.rotateWithRL(t.father.left);
					}
				}
			}
		}
	}

 测试函数:

public static void main(String[] args) {
		// TODO Auto-generated method stub
		RBTree<Integer> t = new RBTree<Integer>(1);
		t.addNode(3);
		t.addNode(4);
		t.addNode(5);
		t.addNode(11);
		t.addNode(512);
		t.addNode(4123);
		t.addNode(7);
		t.addNode(2);
		t.addNode(4);
		System.out.println("中序遍历测试:");
		TreeTools.midOrderTravel(t.getRoot());
		System.out.println("\n前序遍历测试:");
		TreeTools.preOrderTravel(t.getRoot());
		System.out.println("\n后序遍历测试:");
		TreeTools.backOrderTravel(t.getRoot());
		System.out.println("\n层次遍历测试:");
		TreeTools.levelTravel(t.getRoot());
		System.out.println("\n树的深度:"+TreeTools.getTreeDepth(t.getRoot()));
		System.out.println("树的叶子个数:"+TreeTools.getLeafNum(t.getRoot()));
		System.out.println("该树是否是红黑树:"+TreeTools.TreeIsRBTree(t));
		System.out.println("查询测试:"+t.searchNode(3));
		System.out.println("删除值3-------");
		t.delValue(3);
		System.out.println("查询测试:"+t.searchNode(3));
		System.out.println("该树是否是红黑树:"+TreeTools.TreeIsRBTree(t));
	}

 结果:

增加失败,树里已经有值了
中序遍历测试:
1		2		3		4		5		7		11		512		4123		
前序遍历测试:
5		3		1		2		4		512		11		7		4123		
后序遍历测试:
2		1		4		3		7		11		4123		512		5		
层次遍历测试:
5		3		512		1		4		11		4123		2		7		
树的深度:5
树的叶子个数:10
该树是否是红黑树:true
查询测试:true
删除值3-------
查询测试:false
该树是否是红黑树:true

猜你喜欢

转载自709002341.iteye.com/blog/2260634