红黑树

完全参考《Algorithm》edition IV中的相应章节

通过求树的高度来实现对implementation的测试

 

2-3树是一种平衡树,通过自下而上地添加一条数据,往上调整来实现树的平衡,而红黑树就是2-3树的一种实现(把red edge放平就是一棵平衡的2-3树),在红黑树中从根节点到叶子节点的距离计算的是黑色的edge,以此为了维持平衡,在修正红黑树的前后要保证不影响各个支路平衡性

1. 为什么23树能比较平衡呢:每次插入都尽量组成3node树,即保留树的高度不变;然后对红黑树做一些限制(红edge不能连续出现,任意节点的黑色edge数加起来一样),所以一边最多比另外一边多一倍的深度

2. 23树,红黑树是完全平衡的二叉树吗:不是,23树其实只是看起来高度一样,但是3个node的比较了2次;红黑树查找是红色黑色是忽略的

 

 

3种基本操作:

(1)

                   

 

(2)

                 

 

(3)

    

可能有4种需要修改的情况出现,各种情况都对应到23树的insert

 

实现:

 

/*
 * 在这里用的是红黑树实现Map,Set也是一样的
 * test case: insert 2 的幂次个数,最后书的高度应该是logN
 */
public class RedBlackTree<Key extends Comparable<Key>, Value> {
	
	private static final boolean RED = true;
	private static final boolean BLACK = false;
	
	private Node root;
	
	private class Node {
		Key key;
		Value val;
		Node left, right;
		boolean color;					// 定义为进入该node的edge是不是红色edge
		private Node(Key key, Value val, boolean color) {
			this.key = key;
			this.val = val;
			this.color = color;
		}
		
	}
	
	private boolean isRed(Node x) {
		if(x == null)	return false;	// null links are black, because red means merge to top
		return x.color == RED;
	}
	
	
	/*
	 * 有3种情况需要处理
	 * 1. rotate left
	 * 2. rotate right (暂时的)
	 * 3. flip color
	 * 3个函数入参是最顶端的node, 返回的也都是最顶端的node,这一点在insert的时候很重要
	 */
	
	// 1. rotate left
	private Node rotateLeft(Node h) {
		Node x = h.right;
		h.right = x.left;
		x.left = h;
		x.color = h.color;
		h.color = RED;
		return x;
	}
	
	// 2. rotate right
	private Node rotateRight(Node h) {
		Node x = h.left;
		h.left = x.right;
		x.right = h;
		x.color = h.color;
		h.color = RED;
		return x;
	}
	
	// 3. flip color
	private void flipColor(Node h) {
		h.color = RED;
		h.left.color = BLACK;
		h.right.color = BLACK;
	}
	
	
	/*
	 * 实现API:put, find
	 */
	// put 
	public void put(Key key, Value val) {
		root = put(root, key, val);
	}

	private Node put(Node h, Key key, Value val) {
		if(h == null)	return new Node(key, val, RED);
		int cmp = key.compareTo(h.key);
		if(cmp < 0)			h.left = put(h.left, key, val);
		else if(cmp > 0)	h.right = put(h.right, key, val);
		else				h.val = val;
		
		/*
		 * 按照顺序判断是不是需要调整,有可能三者都会执行到,而且往回递归的时候还要check这3项
		 * 因为3种情况都有可能执行,所以修正时返回最顶端的元素很重要
		 * 其实就是按照最复杂的那个调整情况来
		 */
		if(isRed(h.right) && !isRed(h.left))	h = rotateLeft(h);
		if(isRed(h.left) && isRed(h.left.left))	h = rotateRight(h);
		if(isRed(h.left) && isRed(h.right))		flipColor(h);
			
		return h;		// h可能调整过了,所以要返回
	}
	
	
	// height, only for test
	public int height() {
		return height(root);
	}

	private int height(Node h) {
		if(h == null)	return 0;
		return 1 + Math.max(height(h.left), height(h.right));
	}
}

 

 

 

 

 

测试:

 

public class Test {
	public static void main(String[] args) {
		RedBlackTree<Integer, Integer> tree = new RedBlackTree<Integer, Integer>();
		for(int i=0; i<=256; i++)
			tree.put(i, i);
		System.out.println(tree.height());	// assert to be 9
		
		for(int i=512; i>=257; i--)
			tree.put(i, i);
		System.out.println(tree.height());	// assert to be 10
	}
}

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值