java--实现二叉排序树

          树用的很少,一般情况下树都是作为接口被实现的。

          实现二叉排序树:

         首先,二叉排序树最基本的特点:  应该有初始化,即构造函数;其次应该有增删查操作。删除操作有一个简便做法,是给每个节点增加一个boolean型的是否可用标志,查询相应节点然后将标志置为false即可。

          首先,用面向对象的思想建树,树和节点应该分开,如果业务上想给整颗树加什么属性也方便。

树的定义:

/**  
* BinarySortTree:二叉排序树
* @author xuejupo  [email protected] 
* create in 2015-11-19 下午5:28:19  
*    
*/
public class BinarySortTree<T extends Comparable<? super T>> implements Tree<T> {
	
	TreeNode<T> root;

 只是有个根节点而已,可以加上其他的属性,比如最大深度,节点个数,树是否可用等等。

     构造函数:

/**  
	* 类BinarySortTree.java的构造函数
	* <p>Title: </p>  
	* <p>Description: </p>  创建一个空的二叉搜索树
	* createTime: 下午3:27:13  
	*/
	BinarySortTree(){
		root = new TreeNode<T>();
	}
	
	/**  
	* 类BinarySortTree.java的构造函数
	* <p>Title: </p>  
	* <p>Description: </p>  创建一个根节点值为value的二叉搜索树
	* createTime: 下午3:27:23
	* @param value  
	*/
	BinarySortTree(T value) {
		root = new TreeNode<T>(value);
		// TODO Auto-generated constructor stub
	}
	
	BinarySortTree(TreeNode<T> node) {
		root = node;
		// TODO Auto-generated constructor stub
	}

 很简单的一些基本方法:

/**  
	* isEmpty: 是否为空
	* @return 
	* boolean  返回类型   
	*/
	public boolean isEmpty(){
		return this == null || this.root == null;
	}
	/**  
	* getMin: 获取最小值
	* @return 
	* T  返回类型   
	*/
	public T getMin(){
		while(root.leftChild != null){
			root = root.leftChild;
		}
		return root.value;
	}
	
	/**  
	* getMin: 获取root下的最小的节点
	* @return 
	* T  返回类型   
	*/
	public T getMin(TreeNode<T> root){
		while(root.leftChild != null){
			root = root.leftChild;
		}
		return root.value;
	}
	
	/**  
	* getMax:  获取root子树中最大的节点
	* @return 
	* T  返回类型   
	*/
	public T getMax(TreeNode<T> root){
		while(root.rightChild != null){
			root = root.rightChild;
		}
		return root.value;
	}
	
	/**  
	* getMax:  获取最大值
	* @return 
	* T  返回类型   
	*/
	public T getMax(){
		while(root.rightChild != null){
			root = root.rightChild;
		}
		return root.value;
	}

 插入节点:  递归,还是递归。。   写过操作树代码的人应该都清楚,树这种数据结构实在太适合应递归了。。 排序树插入,如果节点小于当前节点,递归当前节点左子树,否则递归右子树。。

/**  
	* addNode: 二叉排序树的插入
	* @param root
	* @param value 
	* void  返回类型   
	*/
	public void addNode(T value) {
		if (root == null) {
			return;
		}
		addNode(root,value);
	}
	public void addNode(TreeNode<T> node,T value) {
		if (node.value.compareTo(value) < 0) {
			if (node.rightChild == null) {
				node.addRight(value);
			} else {
				addNode(node.rightChild, value);
			}
		} else if (node.value.compareTo(value) > 0) {
			if (node.leftChild == null) {
				node.addLeft(value);
			} else {
				addNode(node.leftChild, value);
			}
		} else {
			// 不允许相同元素插入
		}
	}

 查询:还是递归,跟插入类似

/**  
	* searchNode: 在二叉排序树中查询值value是否存在
	* @param value  插入的值
	* @return 
	* TreeNode  返回类型   
	*/
	public boolean searchNode(T value) {
		return searchNode(root,value)  != null;
	}
	
	/**  
	* searchNode: 在二叉排序树中查询值value所在的节点
	* @param root  根节点
	* @param value  插入的值
	* @return 
	* TreeNode  返回类型   
	*/
	private TreeNode<T> searchNode(TreeNode<T> root, T value) {
		if (root == null) {
			return null;
		}
		if (root.value.compareTo(value) == 0) {
			return root;
		}
		if (root.value.compareTo(value) < 0) {
			return searchNode(root.rightChild, value);
		}
		return searchNode(root.leftChild, value);
	}

 删除:可能麻烦点,因为要分几种情况: 要删除的节点是叶子节点,这中情况最简单。   要删除的节点有左子树怎么办,要删除的节点有右子树怎么办,要删除的节点既有左子树又有右子树怎么办。。  还要考虑要删除的节点正好是根节点怎么办。。。

      注释写的很清楚了,有什么不明白的可以留言问我,菜鸟互助,共同进步  

/**  
	* delNode: 二叉排序树中删除节点
	* @param root  根节点
	* @param value   删除的值
	* @return 
	* TreeNode  返回类型   
	*/
	private BinarySortTree<T> delNode(T value) {
		return new BinarySortTree<T>(delNode(root,value));
	}
	/**  
	* delNode: 二叉排序树中删除节点
	* @param root  根节点
	* @param value   删除的值
	* @return 
	* TreeNode  返回类型   
	*/
	private TreeNode<T> delNode(TreeNode<T> root, T value) {
		TreeNode<T> delNode = searchNode(root, value);
		if (delNode == null) {
			return root;
		}
		TreeNode<T> father = getFatherNode(root, value);
		// 如果要删除的是叶子节点
		if (delNode.leftChild == null && delNode.rightChild == null) {
			// 如果要删除的是根节点
			if (father == null) {
				root = null;
			}
			if (father.value.compareTo(delNode.value) < 0) {
				father.rightChild = null;
			} else {
				father.leftChild = null;
			}
			delNode = null;
		} else if (delNode.rightChild == null) {// 如果要删除的节点只有左子树
			// 如果要删除的是根节点
			if (father == null) {
				root = root.leftChild;
			} else {
				if (father.value.compareTo(delNode.value) < 0) {
					father.rightChild = delNode.leftChild;
				} else {
					father.leftChild = delNode.leftChild;
				}
				delNode = null;
			}
		}else if (delNode.leftChild == null) {// 如果要删除的节点只有右子树
			// 如果要删除的是根节点
			if (father == null) {
				root = root.rightChild;
			} else {
				if (father.value.compareTo(delNode.value) < 0) {
					father.rightChild = delNode.rightChild;
				} else {
					father.leftChild = delNode.rightChild;
				}
				delNode = null;
			}
		}else{			//要删除的节点既有左子树,又有右子树
			//在这里我们取左子树的最大节点作为删除节点的后继
			TreeNode<T> leftMax = delNode.leftChild;
			//后继节点的父节点
			TreeNode<T> leftMaxFather = delNode;
			while(leftMax.rightChild != null){
				leftMaxFather = leftMax;
				leftMax = leftMax.rightChild;
			}
			//先删除后继节点,用后继节点替换要删除的节点
			leftMaxFather.rightChild = leftMax.leftChild;
			delNode.value = leftMax.value;
			leftMax = null;
		}
		return root;
	}

 测试代码:

/**
	 * @Title: main
	 * @Description: 这里用一句话描述这个方法的作用
	 * @param args
	 * @return void 返回类型
	 */
	public static void main(String[] args) {
		BinarySortTree<Integer> tree = new BinarySortTree<Integer>(2);
		tree.addNode(4);
		tree.addNode(3);
		//不能添加相同元素
		tree.addNode(4);
		tree.addNode(7);
		System.out.println("中序遍历二叉树,得到的应该是个有序的序列:");
		TreeTools.midOrderTravel(tree.getRoot());
		System.out.println("\n查找最小数:");
		System.out.println(tree.getMin());
		System.out.println("查找2是否在树里:");
		System.out.println(tree.searchNode(2));
		System.out.println("删除节点2:");
		tree = tree.delNode(2);
		System.out.println("删除后中序遍历二叉树:");
		TreeTools.midOrderTravel(tree.getRoot());
		System.out.println("\n查找2是否在树里:");
		System.out.println(tree.searchNode(2));
	}

 结果:

中序遍历二叉树,得到的应该是个有序的序列:
2	3	4	7	
查找最小数:
2
查找2是否在树里:
true
删除节点2:
删除后中序遍历二叉树:
3	4	7	
查找2是否在树里:
false

猜你喜欢

转载自709002341.iteye.com/blog/2258327