二叉查找树

使二叉树成为二叉查找树的性质是,对于树中的每个节点 X ,它的左子树中所有项的值小于 X 中的值,而它右子树中所有项的值大于 X 中的值。

注意,这意味着该树所有的元素可以用某种一致的方式排序。



首先定义一个节点类:

	private static class BinaryNode<T>{
		T element;
		BinaryNode<T> left;
		BinaryNode<T> right;
		
		
		public BinaryNode( T element ) {
			this( element, null, null );
		}

		public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
			this.element = element;
			this.left = left;
			this.right = right;
		}
		
	}


contains 方法

	public boolean contains( T x ){
		return contains( x, root );
	}
	
	private boolean contains( T x, BinaryNode<T> t ){
		if( t == null )
			return false;
		
		int compareResult = x.compareTo( t.element );
		if( compareResult < 0 ){
			return contains( x, t.left );
		}
		else if( compareResult > 0 ){
			return contains( x, t.right );
		}
		else{
			return true;
		}
	}


findMin 方法和 findMax 方法

递归方法实现:

	public T findMin(){
		if( isEmpty() )
			throw new UnderflowException();
		
		return findMin( root ).element;
	}
	
	/**
	 * 递归的方法
	 * @param t
	 * @return
	 *
	 * Date	  :2012-7-6
	 * Author :GongQiang
	 */
	private BinaryNode<T> findMin( BinaryNode<T> t ){
		if( t == null ){
			return null;
		}
		else if( t.left == null ){
			return t;
		}
		
		return findMin( t.left );
	}
非递归方法实现:

	public T findMax(){
		if( isEmpty() )
			throw new UnderflowException();
		
		return findMax( root ).element;
	}
	
	/**
	 * 循环迭代
	 * @param t
	 * @return
	 *
	 * Date	  :2012-7-6
	 * Author :GongQiang
	 */
	private BinaryNode<T> findMax( BinaryNode<T> t ){
		if( t!= null ){
			while( t.right != null )
				t = t.right;
		}
		
		return t;
	}

insert 方法

为了将 X 插入到数 T 中,你可以像用 contains 那样沿着树查找。如果找到 X ,则什么也不用做(或做一些“更新”)。否则将 X 插入到遍历的路径上的最后一点上。

	public void insert( T x ){
		root = insert( x, root );
	}
	
	private BinaryNode<T> insert( T x, BinaryNode<T> t ){
		if( t == null )
			return new BinaryNode<T>( x, null, null );
		
		int compareResult = x.compareTo( t.element );
		if( compareResult < 0 ){
			t.left = insert( x, t.left );
		}
		else if( compareResult > 0 ){
			t.right = insert( x, t.right );
		}
		else{
			; // 重复,不做任何操作
		}
		
		return t;
	}


remove 方法

如果节点是一片树叶,那么它可以被立即删除;

如果节点有一个儿子,则该节点可以在其父节点调整自己的链绕过该节点后被删除;

如果处理具有两个儿子的节点。一般的删除策略是用其右子树的最小的数据代替该节点的数据并递归地删除那个节点(现在它是空的)。因为右子树中的最小的节点不可能有左儿子,所以第二次 remove 要容易。



	public void remove( T x ){
		root = remove( x, root );
	}
	
	private BinaryNode<T> remove( T x, BinaryNode<T> t ){
		if( t == null )
			return t; // Item not found; do nothing
		
		int compareResult = x.compareTo( t.element );
		if( compareResult < 0 ){
			t.left = remove( x, t.left );
		}
		else if( compareResult > 0 ){
			t.right = remove( x, t.right );
		}
		else if( t.left != null && t.right != null ){ // Two children
			t.element = findMin( t.right ).element;
			t.right = remove( t.element, t.right );
		}
		else{
			t = ( t.left != null )? t.left : t.right;
		}
		
		return t;
	}

如果删除的次数不多,通常使用的策略是懒惰删除:当一个元素要被删除时,它仍留在树中,而只是被标记为删除。这特别是在有重复项时很常用,因为此时记录出现频率数的域可以减 1 。如果树中的实际节点数和“被删除”的节点数相同,那么树的深度预计只是上升一个小的常数,因此,存在一个与懒惰删除相关的非常小的时间损耗。再有,如果被删除的项重新插入的,那么分配一个新单元的开销就避免了。


完整代码:

public class BinarySearchTree<T extends Comparable<? super T>> {

	private static class BinaryNode<T>{
		T element;
		BinaryNode<T> left;
		BinaryNode<T> right;
		
		
		public BinaryNode( T element ) {
			this( element, null, null );
		}

		public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
			this.element = element;
			this.left = left;
			this.right = right;
		}
		
	}
	
	private BinaryNode<T> root;

	public BinarySearchTree() {
		root = null;
	}
	
	public void makeEmpty(){
		root = null;
	}
	
	public boolean isEmpty(){
		return root == null;
	}
	
	public boolean contains( T x ){
		return contains( x, root );
	}
	
	private boolean contains( T x, BinaryNode<T> t ){
		if( t == null )
			return false;
		
		int compareResult = x.compareTo( t.element );
		if( compareResult < 0 ){
			return contains( x, t.left );
		}
		else if( compareResult > 0 ){
			return contains( x, t.right );
		}
		else{
			return true;
		}
	}
	
	public T findMin(){
		if( isEmpty() )
			throw new UnderflowException();
		
		return findMin( root ).element;
	}
	
	/**
	 * 递归的方法
	 * @param t
	 * @return
	 *
	 * Date	  :2012-7-6
	 * Author :GongQiang
	 */
	private BinaryNode<T> findMin( BinaryNode<T> t ){
		if( t == null ){
			return null;
		}
		else if( t.left == null ){
			return t;
		}
		
		return findMin( t.left );
	}
	
	public T findMax(){
		if( isEmpty() )
			throw new UnderflowException();
		
		return findMax( root ).element;
	}
	
	/**
	 * 循环迭代
	 * @param t
	 * @return
	 *
	 * Date	  :2012-7-6
	 * Author :GongQiang
	 */
	private BinaryNode<T> findMax( BinaryNode<T> t ){
		if( t!= null ){
			while( t.right != null )
				t = t.right;
		}
		
		return t;
	}
	
	public void insert( T x ){
		root = insert( x, root );
	}
	
	private BinaryNode<T> insert( T x, BinaryNode<T> t ){
		if( t == null )
			return new BinaryNode<T>( x, null, null );
		
		int compareResult = x.compareTo( t.element );
		if( compareResult < 0 ){
			t.left = insert( x, t.left );
		}
		else if( compareResult > 0 ){
			t.right = insert( x, t.right );
		}
		else{
			; // 重复,不做任何操作
		}
		
		return t;
	}
	
	public void remove( T x ){
		root = remove( x, root );
	}
	
	private BinaryNode<T> remove( T x, BinaryNode<T> t ){
		if( t == null )
			return t; // Item not found; do nothing
		
		int compareResult = x.compareTo( t.element );
		if( compareResult < 0 ){
			t.left = remove( x, t.left );
		}
		else if( compareResult > 0 ){
			t.right = remove( x, t.right );
		}
		else if( t.left != null && t.right != null ){ // Two children
			t.element = findMin( t.right ).element;
			t.right = remove( t.element, t.right );
		}
		else{
			t = ( t.left != null )? t.left : t.right;
		}
		
		return t;
	}
	
	public void printTree(){
		//前序输出
		printTree( root );
	}
	
	private void printTree( BinaryNode<T> t ){
		if( t != null ){
			printTree( t.left );
			System.out.println( t.element );
			printTree( t.right );
		}
	}
}

class UnderflowException extends RuntimeException{
	private static final long serialVersionUID = 1L;
	
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值