算法自学笔记:红黑查找树(2)程序实现

红黑树的所有搜索操作,包括get() min() max() ceiling() floor() rank() select() 等(参数未列出),均和普通二叉树一样,搜索时无视节点颜色即可。

红黑树主要在于其插入操作,上一篇我们讲了对双节点插入的几种情况(文章链接)我们会发现即使最复杂的情况,插入值在两值中间,也可以转化为基础操作。
在这里插入图片描述
下图展示了红黑树插入所有可能的情况:插入值小于左端值,插入值在两值中间,插入值大于右端值。我们可以发现其实所有情况都可以以下列规律化解:
1 如红键在右节点,左旋
2 如红键在左节点,且左节点左子节点也为红键,右旋
3 如左节点和右节点均为红键,变色

插入操作代码如下:

	public void put(Key key, Value value) {
		root = put(root, key, value);
	}
	
	
	private Node put(Node x, Key key, Value value) {
		if (x == null) {
			return new Node(key, value, 1, RED);
		}
		
		// find the correct position
		int cmp = key.compareTo(x.key);
		if (cmp > 0) {
			x.right = put(x.right, key, value);
		} else if (cmp < 0) {
			x.left = put(x.left, key, value);
		} else {
			x.value = value;
		}
		
		// rotation and flip color
		if (isRed(x.left)) {
			x = rotateLeft(x);
		}
		if (isRed(x.left) && isRed(x.left.left)) {
			x = rotateRight(x);
		}
		if (isRed(x.left) && isRed(x.right)) {
			flipColor(x);
		}
		x.count = size(x.left) + size(x.right) + 1;
		return x;
		
	}

前一部分程序和二叉树一样,目的是找到正确插入位置。然后插入后对键进行变换以保证红键永远在左边

红黑树性能分析:
由于不可能连续出现两个红键,且根节点到树底各个路径黑键数相等,红黑树最糟情况高度(所有红键和黑键交替出现),不可能大于最优情况高度(所有键为黑键)的两倍。

因此,红黑树查找及插入操作最糟情况时间复杂度为2logN

对于平均情况,时间复杂度约为logN

最后,给出红黑树目前完整程序(暂时还没有删除操作)

public class RedBlackBSTSymbolTable <Key extends Comparable, Value> {
	
	public static final boolean RED = true;
	public static final boolean BLACK = false;
	
	private class Node {
		private Key key;
		private Value value;
		private Node left;
		private Node right;
		private int count;
		private boolean color;
		private Node(Key key, Value value, int count, boolean color) {
			this.key = key;
			this.value = value;
			this.count = count;
			this.color = color;
		}
	}
	
	
	public Node root;
	
	
	public int size() {
		return size(root);
	}
	
	private int size(Node x) {
		if (x == null) {
			return 0;
		} else {
			return x.count;
		}
	}
	
	// constructor
	public RedBlackBSTSymbolTable () {
		root = null;
	}
	
	
	private boolean isRed(Node x) {
		return x.color;
	}
	
	
	private Node rotateLeft(Node h) {
		Node x = h.right;
		h.right = x.left;
		x.left = h;
		x.color = h.color;
		h.color = RED;
		x.count = h.count;
		h.count = size(h.left) + size(h.right) + 1;
		return x;
	}
	
	
	private Node rotateRight(Node h) {
		Node x = h.left;
		x.right = h.left;
		x.right = h;
		x.color = h.color;
		h.color = RED;
		x.count = h.count;
		h.count = size(h.left) + size(h.right) + 1;
		return x;
	}
	
	
	private void flipColor(Node h) {
		h.left.color = BLACK;
		h.right.color = BLACK;
		h.color = RED;
	}
	
	public void put(Key key, Value value) {
		root = put(root, key, value);
	}
	
	
	private Node put(Node x, Key key, Value value) {
		if (x == null) {
			return new Node(key, value, 1, RED);
		}
		
		// find the correct position
		int cmp = key.compareTo(x.key);
		if (cmp > 0) {
			x.right = put(x.right, key, value);
		} else if (cmp < 0) {
			x.left = put(x.left, key, value);
		} else {
			x.value = value;
		}
		
		// rotation and flip color
		if (isRed(x.left)) {
			x = rotateLeft(x);
		}
		if (isRed(x.left) && isRed(x.left.left)) {
			x = rotateRight(x);
		}
		if (isRed(x.left) && isRed(x.right)) {
			flipColor(x);
		}
		x.count = size(x.left) + size(x.right) + 1;
		return x;
		
	}
	
	
	
	
	// The methods below are the same as those in a regular BST
	// since the searching operations are the same
	
	
	// find a certain value according to its key
	public Value get(Key key) {
		Node result = get(key, root);
		if (result == null) {
			return null;
		}
		return result.value;
	}
	
	private Node get(Key key, Node x) {
		if (x == null) {	// no this key
			return null;
		}
		
		if (x.key.compareTo(key) > 0) {	// smaller, move to the left
			return get(key, x.left);
		} else if (x.key.compareTo(key) < 0) {	// larger, move to the right
			return get(key, x.right);
		} else {
			return x;	// find it
		}
	}
	
	
	// find the smallest key
	public Key min() {
		return min(root).key;
	}
	
	private Node min(Node x) {
		if (x.left == null) {
			return x;
		} else {
			return min(x.left);
		}
	}
	
	
	// find the largest key
	public Key max() {
		return max(root).key;
	}
	
	private Node max(Node x) {
		if (x.right == null) {
			return x;
		} else {
			return max(x.right);
		}
	}
	
	
	// find the largest key less or equals k
	public Key floor (Key k) {
		Node x = floor(root, k);
		if (x == null) {
			return null;
		} else {
			return x.key;
		}
	}
	
	private Node floor(Node x, Key k) {
		if (x == null) {
			return null;
		} 
		int cmp = k.compareTo(x.key);
		if (cmp == 0) {	// the same key, return it
			return x;
		} else if (cmp < 0) {
			return floor(x.left, k);	// smaller, move to the left
		} else {	// larger, attempt to move to the right
			Node t = floor(x.right, k);
			if (t != null) {
				return t;
			} else {
				return x;
			}
		}
	}
	
	
	// find the smallest key larger or equals k
	public Key ceiling (Key k) {
		Node x = ceiling(root, k);
		if (x == null ) {
			return null;
		}
		return x.key;
	}
	
		
	private Node ceiling(Node x, Key k) {
		if (x == null) {
			return null;
		}
		int cmp = k.compareTo(x.key);
		if (cmp == 0) {	// the exact value
			return x;
		} else if (cmp > 0) {
			return ceiling(x.right, k);	// larger, move to the left
		} else {	// smaller, attempt to move to the right
			Node t = ceiling(x.left, k);
			if (t != null) {
				return t;
			} else {
				return x;
			}
		}
	}
	
	
	// return the kth smallest key
	public Key select(int k) {
		Node x = select(k, root);
		if (x == null) {
			return null;
		}
		return x.key;
	}
	
	private Node select(int k, Node x) {
		if (x == null) {
			return null;
		}
		int rank = size(x.left);
		if (rank == k) {	// find the correct index
			return x;
		} else if (rank > k) { // move to the left
			return select(k, x.left);
		} else {	// move to the right
			return select(k - rank - 1, x.right);
		}
	}
	
	
	// find the rank of a given key
	public int rank(Key key) {
		return rank(key, root);
	}
	
	private int rank(Key key, Node x) {
		if (x == null) {
			return 0;
		}
		int cmp = key.compareTo(x.key);
		if (cmp == 0) {	// find the key
			return size(x.left);
		} else if (cmp > 0) {	// smaller, move to the right
			return size(x.left) + 1 + rank(key, x.right);
		} else {	// larger, move to the left
			return rank(key, x.left);
		}
	}
	
	
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值