红黑树(三)

删除操作
1. 在纯函数式的环境下,纯函数式的数据结构决定了树不是真的被改变了,实际上是重建一棵树。(大多数函数式编程环境使用一种名叫Persistent的方法,可以复用树中没有改变的部分,从而减小重建的开销)。
利用一个双重黑色的引入。将删除节点的颜色(黑色)保存在其父节点中,如果父节点红色,则染成黑色,如果父节点是黑色,就是双重黑色。


删除的过程:1、如果删除的这个节点是根节点,root = null。左右节点都为空,直接删除。直接删注意它的颜色是否为黑色,若是黑色删除了违反性质5; 

2、如果删除的这个节点有一个子节点,让它的子节点替代它,再把它删除即可;

3、删除的节点的左右子节点都不是空,找他的替代节点(可能是它的左子节点,或者左子节点的右节点一直遍历下去,即左子树的max, 亦或是右子树的min),然后替代节点替代这个值,将删除节点删除。

删掉后的结果则分为好几种情况(下面的结点为替代替代结点后的结点):

1、结点为新的根,此时只是将所有的路径中都去除一个黑色结点,所以依然保持平衡;
2、结点的兄弟结点为红色;
3、结点的兄弟结点为黑色,同时其子结点也均为黑色;
4、结点的兄弟结点为黑色,同时兄弟结点的左子结点为红色,右子结点为黑色;
5、结点的兄弟结点为黑色,同时兄弟结点的右子结点为红色,左子结点为红色;删除之后通过调整,改变旋转和调整颜色维持红黑树的性质。
注意:x是指向于非根节点的一个双重黑色的节点。

情形1:x(A)的兄弟节点w(D)是红色的。


若D.color=red;则改变x.parent 和w的颜色。但是此时违反了性质5,所以左旋。

情形2:x(A)的兄弟节点w(D)是黑色的,它的两个子节点C、E也是黑色的。


此时给x, w褪去一层黑色。使得变成x(A)变成单黑色。w(D)变换为红色。而x的根节点(B)增加一层红色,变为“红黑色”或者“双重黑色”,此时将x.parent 作为新的x。

情形3:x(A)的兄弟节点w(D)是黑色,兄弟节点的左子节点(C)为红色, 右子节点(D)为黑色。

此时交换w.left.color(C)和w.color(D)的颜色,然后右旋。

情形4:兄弟节点的右子节点是红色

左旋。x(A)褪去一层黑色变为单黑色。B节点变为黑色。当x设置为根后,当while循环测试其循环条件时,结束循环。

参考代码:

//删除指定节点
	public void delete(T element){
		//获取要删除的节点   注意这里是通过查找而不是new
		Node target = tree_search(element);
		if(target.left != null && target.right != null){
			//先找到目标节点中序遍历的前一个节点
			//前一个节点显然在它的左子树中。相当于找左子树的最大值。
			Node tmp = target.left;
			while(tmp.right != null){
				tmp = tmp.right;
			}
			target.data = tmp.data;
			target = tmp;
		}
//		System.out.println(target);
		//修复它的替换节点,如果该替换节点不为Null
		Node replacement = (target.left != null ? target.left : target.right);
//		System.out.println(replacement); --可以为null
		if(replacement != null){

			replacement.parent = target.parent;
			//如果目标节点的父节点为null,那么目标节点自己是根节点
			if(target.parent == null){
				root = replacement;
			}
			//如果target是其父节点的左节点
			else if(target == target.parent.left){
				target.parent.left = replacement;
			}
			else{
				target.parent.right = replacement;
			}
			//删除这个节点
			target.left = target.right = target.parent = null;
			//修复红黑树
			if(target.color == BLACK){
				rbDelect_Fixup(replacement);
			}
		}
		//自身是根节点
		else if(target.parent == null){
			root = null;
		}
		else{
			//target无子节点,把它当成虚的替换节点
			//修复红黑树
			if(target.color == BLACK){
				rbDelect_Fixup(target);
			}
			if(target.parent != null){
				if(target ==target.parent.left){
					target.parent.left = null;
				}
				else if(target ==target.parent.right){
					target.parent.right = null;
				}
				target.parent = null;
			}
		}
	}
//删除节点后修复红黑树
	private void rbDelect_Fixup(Node T) {
		while(T != root && colorOf(T) == BLACK){
			//T是其父节点的左节点
			if(T == leftOf(parentOf(T))){
				//获取它的兄弟节点
				Node brother = rightOf(parentOf(T));
				if(brother.color == RED){
					//兄弟节点设置为黑色。
					setColor(brother, BLACK);
					//父节点设置为红色
					setColor(parentOf(T), RED);
					rotateLeft(parentOf(T));
					//将兄弟节点设置为删除节点的父节点的右节点。
					brother = rightOf(parentOf(T));
				}
				if(colorOf(leftOf(brother)) == BLACK && colorOf(rightOf(brother)) == BLACK){
                    //
					setColor(brother, RED);
					T = parentOf(T);
				}
				else{
					//只有兄弟节点的右节点是黑色
					if(colorOf(rightOf(brother)) == BLACK){
						//左节点也设置为黑色
						setColor(leftOf(brother), BLACK);
						setColor(brother, RED);
						rotateRight(brother);
						brother = rightOf(parentOf(T));
					}
					//设置兄弟接待你的颜色和父节点一样
					setColor(brother, colorOf(parentOf(T)));
					//T的父节点设置成黑色
					setColor(parentOf(T), BLACK);
					//brother的右节点设置为黑色
					setColor(rightOf(brother), BLACK);
					rotateLeft(parentOf(T));
					T = root;
				}
			}
			//如果T是其父节点的右子节点
			else{
				//获取T的兄弟节点
				Node brother = leftOf(parentOf(T));
				if(brother.color == RED){
					//兄弟节点设置为黑色。
					setColor(brother, BLACK);
					//父节点设置为红色
					setColor(parentOf(T), RED);
					rotateRight(parentOf(T));
					//将兄弟节点设置为删除节点的父节点的右节点。
					brother = leftOf(parentOf(T));
				}
				if(colorOf(leftOf(brother)) == BLACK && colorOf(rightOf(brother)) == BLACK){

					setColor(brother, RED);
					T = parentOf(T);
				}
				else{
					//只有兄弟节点的左节点是黑色
					if(colorOf(leftOf(brother)) == BLACK){
						//brother的右节点也设置为黑色
						setColor(rightOf(brother), BLACK);
						setColor(brother, RED);
						rotateLeft(brother);
						brother = leftOf(parentOf(T));
					}
					//设置兄弟接待你的颜色和父节点一样
					setColor(brother, colorOf(parentOf(T)));
					//T的父节点设置成黑色
					setColor(parentOf(T), BLACK);
					//brother的右节点设置为黑色
					setColor(rightOf(brother), BLACK);
					rotateLeft(parentOf(T));
					T = root;
				}
			}
		}
		setColor(T, BLACK);		
	}


参考书籍:《算法导论》《疯狂Java突破程序员基本功的16课》

以上就是这篇的主要内容,欢迎提出意见,此外图片制作粗糙,请见谅。谢谢!

猜你喜欢

转载自blog.csdn.net/kobe_jr/article/details/80138809