BST小结

BST作为符号表的数据结构,很重要的一种。本文将前文中的实现内容汇聚在一起,在经过测试用例测试通过后,可以将实现好版本作为自己的库,以供调用。如果对该api有不同的实现,可以编写不同的实现,如果测试通过,则表明实现正确。

被Client端使用的类型需要经过测试,否则可能扰乱client端代码。

共同构成BST这个类型的一个实现版本。

下面是api


下面是实现:
public class BST<Key extends Comparable<Key>, Value> {
	private Node root;

	class Node {
		private Key key;
		private Value value;
		private Node left, right;
		private int count; // 子树节点个数,算上根

		// 节点构造方法
		public Node(Key k, Value v, int c) {
			key = k;
			value = v;
			count = c;
		}

		public Key getKey() {
			return key;
		}
	}

	// BST构造方法
	public BST() {
		root = null;
	}

	// 插入元素
	public void put(Key k, Value v) {
		root = put(root, k, v);

	}

	// 插入子方法.
	private Node put(Node x, Key k, Value v) {
		if (x == null)
			return new Node(k, v, 1);
		Node t = new Node(k, v, 1);

		// 与当前key相比
		int cmp = k.compareTo(x.key);

		if (cmp < 0)// 插入到左链接上
			x.left = put(x.left, k, v);
		else if (cmp > 0) // 插入到右链接上
			x.right = put(x.right, k, v);
		else
			// 更新元素的value
			x.value = v;
		x.count = size(x.left) + size(x.right) + 1;
		return x;

	}

	// 整个树的大小
	public int size() {
		return size(root);
	}

	// 任意一个子树的大小
	private int size(Node x) {
		if (x == null)
			return 0;
		else
			return size(x.left) + size(x.right) + 1;
	}

	// 在整棵树中获取key的值
	public Value get(Key k) {
		return get(root, k);
	}

	// 指定树下获取key的值
	private Value get(Node x, Key k) {
		if (x == null)
			return null;
		// 与当前x的key比较
		int cmp = k.compareTo(x.key);
		if (cmp < 0)
			return get(x.left, k);
		else if (cmp > 0)
			return get(x.right, k);
		else
			return x.value;

	}

	// 在整个树上删除key的节点
	/**
	 */
	public void delete(Key k) {
		root = delete(root, k);
	}

	// 删除以x为根的树中的key的节点,返回该树根,更改型操作要维护count
	/***********************
	 * 0.找到该key 1.没有孩子 2.一个孩子 3.二个孩子 *
	 */
	private Node delete(Node x, Key k) {
		if (x == null)
			return null;
		int cmp = k.compareTo(x.key);
		if (cmp < 0)
			x.left = delete(x.left, k);
		else if (cmp > 0)
			x.right = delete(x.right, k);
		else {
			// 找到这个key的节点
			if (x.left == null)
				return x.right;
			if (x.right == null)
				return x.left;
			// 有2个孩子
			Node t = x;
			x = min(t.right);
			x.right = deleteMin(t.right);
			x.left = t.left;

		}
		x.count = size(x.left) + size(x.right) + 1;
		return x;
	}

	// 删除最小节点,该节点没有左链接
	private Node deleteMin(Node x) {
		if (x.left == null)
			return x.right;
		x.left = deleteMin(x.left);
		x.count = size(x.left) + size(x.right) + 1;
		return null;
	}

	public Node min() {
		return min(root);
	}

	// 返回以x为根的最小节点
	private Node min(Node x) {
		if (x == null)
			return null;
		while (x.left != null)
			x = x.left;
		return x;
	}

	// 中序打印,用于验证删除操作
	public void print() {
		print(root);
	}

	private void print(Node x) {
		if (x == null)
			return;
		print(x.left);
		System.out.println(x.key + " " + x.value);
		print(x.right);
	}

	/********** 与顺序有关的2个api *********/
	// 给定key,求排第几
	/**
	 * 3 cases. 
	 * (1) key < x.key。返回在左子树中 的排名 
	 * (2) key > x.key. 先计算右子树排名,加上x左子树个数+1
	 * (3) key == x.key.返回左子树size()+1
	 **/
	public int rank(Key key) {
		return rank(root, key);
	}

	private int rank(Node x, Key k) {
		if (x == null)
			return 0;
		// 根x比较
		int imp = k.compareTo(x.key);
		if (imp < 0)
			return rank(x.left, k);
		if (imp > 0)
			return rank(x.right, k) + size(x.left) + 1;
		else
			return size(x.left) + 1;
	}

	/**
	 * 3 cases. r是当前节点排名
	 *  (1) i < r。返回在左子树中 的的第i小的key 
	 *  (2) i > r. 返回在右子树中第(i-r)的key 
	 *  (3) i == r 返回key
	 **/
	// 返回拍第i的Key
	public Key select(int i) {
		return select(root, i);
	}

	private Key select(Node x, int i) {
		if (x == null)
			return null;
		// 根x的排名比较
		int r = size(x.left) + 1;

		if (i < r)
			return select(x.left, i);
		if (i > r)
			return select(x.right, i - r);
		else
			return x.key;
	}

	/***** BST另外2个基于顺序,或者比较操作的api ********/
	/****
	 * public Key floor(Key key) 在整个树中,返回小于等于给定key的最大Key
	 * public Key ceiling(Key key)在这个树种,返回大于等于给定key的最小key
	 * 
	 * 这个2个操作思路与rank,select的关系一样,都是以“相反”的操作,所以
	 * 只要实现一个,另一个就非常easy
	 */

	public Key floor(Key key) {
		return floor(root,key);
	}

	// 在以x为根的树种,返回"比key小或等的最大数"
	/****
	 * 在实现时,可以这样理解这个操作:"数轴法" 
	 * 在数轴上,比x.key小的数都在左边,比x.key的树都在右边。
	 * case1: k<x.key 返回floor(x.left,k) 
	 * case2: k>x.key 如果floor(x.right,k)不为空,则返回,否则返回x.key
	 * case3: k==x.key 返回x.key
	 */
	private Key floor(Node x, Key k) {
		if(x==null) return null;
		//开始比较
		int cmp = k.compareTo(x.key);
		if(cmp<0) return floor(x.left, k);
		if(cmp==0) return x.key;
		//习惯上把最复杂的放在最后边,而且如果if后面有return,则不需要else
		else
		{
			Key t = floor(x.right,k);
			if(t!=null) return t;
			else return x.key;
			
		}
	}
	public Key ceiling(Key key) {
		return ceiling(root,key);
	}

	// 在以x为根的树种,返回"比key大或等的最小数"
	/****
	 * 在实现时,可以这样理解这个操作:"数轴法" 
	 * 在数轴上,比x.key小的数都在左边,比x.key的树都在右边。
	 * case1: k<x.key 返回 ceiling(x.left,k)不为空,则返回,否则返回x.key
	 * case2: k>x.key 如果ceiling(x.right,k)
	 * case3: k==x.key 返回x.key
	 */
	private Key ceiling(Node x, Key k) {
		if(x==null) return null;
		//开始比较
		int cmp = k.compareTo(x.key);
		if(cmp>0) return ceiling(x.right, k);
		if(cmp==0) return x.key;
		//习惯上把最复杂的放在最后边,而且如果if后面有return,则不需要else
		else
		{
			Key t = ceiling(x.left,k);
			if(t!=null) return t;
			else return x.key;
			
		}
	}

}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值