码迷,mamicode.com
首页 > 编程语言 > 详细

RBT红黑树-JAVA版本

时间:2015-04-14 13:04:52      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:红黑树   平衡树   java   数据结构   

这个玩意代码量巨大,模仿着别人写了整整一天...

Java因为没有引用传递,所以构建树要么是全局设定根然后更改,要么函数返回的是根.....

参考:教你透彻理解红黑树   数据结构-红黑树

红黑树确保没有一条路径比其他的路径长出2倍左右,因而是接近平衡的

1. 红黑树性质(限制):

1)每个结点要么是红的要么是黑的。  
2)根结点是黑的。  
3)每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。  
4)如果一个结点是红的,那么它的两个儿子都是黑的。  
5)对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。

2. 红黑树的性能分析:

挖坑,明天写.


3.预备知识:

左旋(右旋)指的是将这个点的右(左)子树占据自己的位置,原来的点变为其左(右)子树.

技术分享

4.核心操作:

1) 插入

和AVL差不多,就是有个调整颜色的过程

	/* 
	 * 如果父节点是黑色就都没违反不用调整.
	 * 反之....
	 * 插入一个结点时。可能被破坏的性质为(4)如果一个结点是红色的,则它的孩子结点是黑色的   (2) 根结点是黑色的 
	 * 插入修复情况1:如果当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色
         * 插入修复情况2:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子
 	 * 插入修复情况3:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子
	*/


2)删除

比较复杂,四种情况...

/* 
	* 如果删除的是红色点,没影响........
	* 如果删除的是黑色点,代替它位置的有红/黑两种情况,
	* 1. 红,直接将这个点改成黑色
	* 2.1 黑且是根节点什么都不用做
	* 2.2 删除修复情况1,当前节点颜色是黑,兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑)
	* 2.2删除修复情况2,当前节点颜色是黑,兄弟是黑色且兄弟节点的两个子节点全为黑色
	* 2.2删除修复情况3,当前节点颜色是黑,兄弟节点是黑色,兄弟的左子是红色,右子是黑色
	* 2.2删除修复情况4,当前节点颜色是黑,兄弟节点是黑色,但是兄弟节点的右子是红色,
*/

代码:

import java.util.Arrays;
import java.util.Collection;
import java.util.Scanner;
interface ANode{
	public void rbInorderTravel(Node node);
	public Node rbSearch(Node node);
	public Node rbMinNode(Node node);
	public Node rbMaxNode(Node node);
	public boolean rbInsert(Node node,int data);
	public boolean rbDelete(Node node,int data);
	public void LL(Node node);
	public void RR(Node node);
	
}
public class Main {
	
	public static void main(String[] args) {
		int [] a = new int[20];
		for(int i = 0;i<20;i++){
			a[i] = (int) (Math.random()*1000);
			System.out.print(a[i] + " ");
			Node.rbInsert(Node.root, a[i]);
		}System.out.println();
		Node.rbInorderTravel(Node.root);
		Node.rbDelete(Node.root, a[1]);
		Node.rbDelete(Node.root, a[9]);
		Node.rbDelete(Node.root, a[0]);
		Node.rbInorderTravel(Node.root);
	}
}

class Node{
	public static Node root = null;
	public static int RED = 1;
	public static int BLACK = 2;
	Node lson,parent,rson;
	int high;
	int data;
	int color;
	public Node() {
		super();
		lson = rson = null;
		high = 0;
		this.color = RED;
	}

	public Node(int data) {
		// TODO Auto-generated constructor stub
		this();
		this.data = data;
	}
	public void free(){
		this.lson = this.rson = null;
		this.parent = null;
	}
	public static Node rbSearch(Node node,int data){
		while(node != null){
			if(data < node.data)
				node = node.lson;
			else if(data > node.data)
				node = node.rson;
			else return node;
		}
		return null;
	}
	public static Node rbSuccessor(Node node){
		Node pre = null;
		while(node != null){
			pre = node;
			node = node.lson;
		}
		return pre;
	}

	public static void rbInorderTravel(Node node) {
		// TODO Auto-generated method stub
		if(null == node)
			return;
		rbInorderTravel(node.lson);
		System.out.print(node.data+" ");
		rbInorderTravel(node.rson);
		if(node == root)
			System.out.println();
	}

	public static boolean rbInsert(Node node, int data) {
		// TODO Auto-generated method stub
		Node now = new Node(data);
		Node pre = null;
		while(null != node){
			pre = node;
			if(data < node.data)
				node = node.lson;
			else node = node.rson;
		}
		if(pre == null)
			root = now;
		else{
			if(data < pre.data)
				pre.lson = now;
			else pre.rson = now;
		}
		now.parent = pre;
		rbTreeInsertFixup(now);
		return true;
	}
	/* 
	 * 如果父节点是黑色就都没违反不用调整.
	 * 反之....
	 * 插入一个结点时。可能被破坏的性质为(4)如果一个结点是红色的,则它的孩子结点是黑色的   (2) 根结点是黑色的 
	 * 插入修复情况1:如果当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色
     * 插入修复情况2:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子
 	 * 插入修复情况3:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子
	*/
	private static void rbTreeInsertFixup(Node node) {
		// TODO Auto-generated method stub
		Node uncle,gparent,p;
		while((p=node.parent) != null && p.color ==RED){
			gparent = p.parent;
			//如果父结点是祖父结点的左孩子(因为父结点是红色结点,所以肯定有祖父结点)  
			if(p == gparent.lson){
				uncle = gparent.rson;
				if(uncle != null && uncle.color == RED){//修复情况1
					gparent.color = RED;
					p.color = BLACK;
					uncle.color = BLACK;
					node = gparent;
				}else{  //叔父不存在或者存在但是颜色是黑色的,则必须通过寻转来配合改变颜色来保持性质2
					if(node == p.rson){//修复情况2
						node = p;
						LL(node);
						p = node.parent;
					}// 情况2:x为其父结点的右孩子,通过左旋转换为情况3  
					//情况三:x为其父结点的左孩子,调整父结点和祖父结点的颜色,以纠正性质4,但是破坏了性质5  
					p.color = BLACK;
					gparent.color = RED;
					RR(gparent);//此时x->parent->color = BLACK, 循环结束
				}
			}else{
				uncle = gparent.lson;
				if(uncle != null && uncle.color == RED){
					gparent.color = RED;
					p.color = BLACK;
					uncle.color = BLACK;
					node = gparent;
				}else{  //叔父不存在或者存在但是颜色是黑色的,则必须通过寻转来配合改变颜色来保持性质2
					if(node == p.lson){
						node = p;
						RR(node);
						p = node.parent;
					}// 情况2:x为其父结点的右孩子,通过左旋转换为情况3  
					//情况三:x为其父结点的左孩子,调整父结点和祖父结点的颜色,以纠正性质4,但是破坏了性质5  
					p.color = BLACK;
					gparent.color = RED;
					LL(gparent);//此时x->parent->color = BLACK, 循环结束
				}
			}
		}
		root.color = BLACK;//保持性质2,根为黑色
	}
	  
	/* 
	* 如果删除的是红色点,没影响........
	* 如果删除的是黑色点,代替它位置的有红/黑两种情况,
	* 1. 红,直接将这个点改成黑色
	* 2.1 黑且是根节点什么都不用做
	* 2.2 删除修复情况1,当前节点颜色是黑,兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑)
	* 2.2删除修复情况2,当前节点颜色是黑,兄弟是黑色且兄弟节点的两个子节点全为黑色
	* 2.2删除修复情况3,当前节点颜色是黑,兄弟节点是黑色,兄弟的左子是红色,右子是黑色
	* 2.2删除修复情况4,当前节点颜色是黑,兄弟节点是黑色,但是兄弟节点的右子是红色,
	* 
	* 另一种解释:
	* 删除一个黑结点会导致如下三个问题:  
	* (1)如果被删除结点y是根结点,而y的一个红色孩子成为了新的根,则违反了性质2 
	* (2)如何y的父结点和其孩子结点都是红色的,则违反了性质4 
	* (3)删除y将导致先前包含y的任何路径上的黑结点树少一个,破坏了性质5。 
	* 解决方案是:被删除的结点黑色属性下移到其孩子结点x上。此时性质5都得以保持,于是存在2种情况: 
	* (1)x原来为红色,此时孩子结点属性是红黑,此时破坏了性质(1),(4),如果x还是树根则,破坏了性质(2) 
	*       处理方式为:将x重新着色为黑色(此操作同时去除其多余的黑色属性),处理完毕,红黑树性质得以保持 
	* (2)x原来为黑色,此时x的属性为双重黑色,破坏了性质(1),若x为树根,则可以只是简单的消除x多余的黑色属性 
	*       否则需要做必要的旋转和颜色修改 
	*/  
	public static boolean rbDelete(Node node, int data) {
		// TODO Auto-generated method stub
		Node now = rbSearch(node,data);
		Node pre = now;
		Node son = null;
		if(now == null)
			return false;
		if(now.lson != null && now.rson != null){
			now = rbSuccessor(now.rson);
			pre.data = now.data;
		}else if(now.lson != null)
			son = now.lson;
		 else if(now.rson != null)
			son = now.rson;
		
		if(son != null)
			son.parent = now.parent;
		if(now.parent == null)
			root = son;
		else{
			if(now.parent.lson == now)
				now.parent.lson = son;
			else now.parent.rson = son;
		}
		if(now.color == BLACK)
			rbTreeDeleteFixup(root,now.parent,son); 
		now.free();
		return true;
	}

	private static void rbTreeDeleteFixup(Node root,Node parent, Node node) {
		// TODO Auto-generated method stub
		Node brother = null;
		while( ( node==null || node.color==BLACK ) && node != root){
			if(node == parent.lson){
				brother = parent.rson;
				//情况1:如果兄弟结点为红色,则parent颜色比为黑色,此时调整颜色,并左旋,使得brother和  
				//parent位置调换,此操作不破坏别的性质,并将情况1变化为情况2,3,4  
				if(brother.color == RED){
					parent.color = RED;
					brother.color = BLACK;
					LL(parent);
					brother = parent.rson;
				}
				 //情况2,这里没有加brother==black是因为经过情况1定然满足
				 //brother有两个黑色结点(NULL也为黑色结点):将x和brother抹除一重黑色  
				 //具体操作为,brother的颜色变为红,x结点上移到其父结点
				if((brother.lson == null || brother.lson.color == BLACK) && 
					(brother.rson == null || brother.rson.color == BLACK)){
					brother.color = RED;
					node = parent;
					parent = parent.parent;
				}else{
					//从上面的if中已经知道两个孩子不都是黑色
					//情况3: brother左孩子为红色结点,右孩子为黑色结点  
					if(brother.rson == null || brother.rson.color == BLACK){
						brother.lson.color = BLACK;
						brother.color = RED;
						RR(brother);//右旋使情况3变化为情况4 
						brother = parent.rson;//因为旋转,重置
					}
					//情况4:brother的右孩子为红色结点:  
	                //交换brother和parent的颜色和位置,使得x的2重黑色属性中的一重转移到其parent上  
	                //此时到brother的右孩子的黑结点数少一,于是将右结点的颜色置黑,红黑树性质得以保持 
					brother.color = parent.color;
					parent.color = BLACK;
					brother.rson.color = BLACK;
					LL(parent);
					node = root;
				}
			}else{
				brother = parent.lson;
				//情况1:如果兄弟结点为红色,则parent颜色比为黑色,此时调整颜色,并左旋,使得brother和  
				//parent位置调换,此操作不破坏别的性质,并将情况1变化为情况2,3,4  
				if(brother.color == RED){
					parent.color = RED;
					brother.color = BLACK;
					RR(parent);
					brother = parent.lson;
				}
				 //情况2,这里没有加brother==black是因为经过情况1定然满足
				 //brother有两个黑色结点(NULL也为黑色结点):将x和brother抹除一重黑色  
				 //具体操作为,brother的颜色变为红,x结点上移到其父结点
				if((brother.lson == null || brother.lson.color == BLACK) && 
					(brother.rson == null || brother.rson.color == BLACK)){
					brother.color = RED;
					node = parent;
					parent = parent.parent;
				}else{
					//从上面的if中已经知道两个孩子不都是黑色
					//情况3: brother右孩子为红色结点,左孩子为黑色结点  
					if(brother.lson == null || brother.lson.color == BLACK){
						brother.rson.color = BLACK;
						brother.color = RED;
						LL(brother);//右旋使情况3变化为情况4 
						brother = parent.rson;//因为旋转,重置
					}
					//情况4:brother的右孩子为红色结点:  
	                //交换brother和parent的颜色和位置,使得x的2重黑色属性中的一重转移到其parent上  
	                //此时到brother的右孩子的黑结点数少一,于是将右结点的颜色置黑,红黑树性质得以保持 
					brother.color = parent.color;
					parent.color = BLACK;
					brother.lson.color = BLACK;
					RR(parent);
					node = root;
				}
			}
		}
		if(node != null)
			node.color = BLACK;
	}
	/**
	 * 红黑树的左转与AVL的不同,LL是root.left.right提上去
	 * @param node
	 */
	public static void LL(Node node) {
		// TODO Auto-generated method stub
		Node son = node.rson;
		node.rson = son.lson;
		if(son.lson != null)
			son.lson.parent = node;
		son.parent = node.parent;
		//node 为树根
		if(node.parent == null)
			root = son;
		else{
			if(node.parent.lson == node)
				node.parent.lson = son;
			else node.parent.rson = son;
		}
		son.lson = node;
		node.parent = son;
	}

	public static void RR(Node node) {
		// TODO Auto-generated method stub
		Node son = node.lson;
		node.lson = son.rson;
		if(son.rson != null)
			son.rson.parent = node;
		son.parent = node.parent;
		//node 为树根
		if(node.parent == null)
			root = son;
		else{
			if(node.parent.lson == node)
				node.parent.lson = son;
			else node.parent.rson = son;
		}//要修改parent,parent的左右,本身指针
		son.rson = node;
		node.parent = son;
	}
	
}



RBT红黑树-JAVA版本

标签:红黑树   平衡树   java   数据结构   

原文地址:http://blog.csdn.net/gg_gogoing/article/details/45039115

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!