二叉查找树是树ADT的一种,它的性质是对于树中的每个节点X,它的左子树中所有项的值均小于X的值,而X的右子树中所有项的值均大于X的值。
*ADT:抽象数据类型:带有一组操作的一些对象的集合。
一个简单的二叉查找树如图所示:
二叉查找树要求所有的项能够排序,我们需要提供一个interface来表示这个性质,这个接口就是Comparable,实现这个接口,树中的两项总可以使用compareTo方法进行比较。
在二叉查找树的实现类BinarySearchTree中只有一个唯一的数据域,这个数据域表示对根节点的引用,在空树中,这个引用是Null。
节点是用BinaryNode这个内部泛型类来实现,包含三个数据域,一个是当前节点值,一个是对左儿子的引用,一个是对右儿子的引用。
包含以下方法的实现:
1、contains(AnyType x, BinaryNode<AnyType> t)
如果树中存在含有项X的节点,那么这个方法返回true,如果树中不包含这个节点,则返回false
2、findMIn和findMax
findMin,从根开始并且只要有左儿子就向左遍历,终止点就是最小元素。findMax,从根节点开始并且只要有右儿子就向右遍历,终止点就是最大元素。
3、insert
从根节点开始遍历,如果遍历到插入值X,则什么也不做,否则将X插入到遍历路径上的最后一个节点上。
4、remove
如果节点是一片树叶,则立即删除。如果节点有一个儿子,则将当前节点设为其左/右儿子节点。如果节点有两个儿子,用其右子树中最小的节点替代该节点,并将这个最小节点删除。
5、printTree
打印该树
实现代码如下:
/**
* @description
* @author Zhangx
* @date 2015年12月3日 下午7:36:08
* @version 1.0
*/
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>>{
private BinaryNode<AnyType> root; //对二叉查找树根节点的引用
/**
* 初始化,默认为空树
*/
public BinarySearchTree(){
root = null;
}
/**
* 清空当前的二叉查找树
*/
public void makeEmpty(){
root = null;
}
/**
* 该树是否为空树
* @return boolean
*/
public boolean isEmpty(){
return root == null;
}
/**
* 查找树中是否有元素X
* @param x
* @return boolean
*/
public boolean contains(AnyType x){
return contains(x, root);
}
/**
* 查找最小值,如果是空树则抛出异常
* @return boolean
*/
public AnyType findMin(){
if(isEmpty())
throw new UnderflowException();
return findMin(root).element;
}
/**
* 查找最大值,如果是空树则抛出异常
* @return boolean
*/
public AnyType findMax(){
if(isEmpty())
throw new UnderflowException();
return findMax(root).element;
}
/**
* 插入元素X
* @param x
*/
public void insert(AnyType x){
root = insert(x, root);
}
/**
* 在树中删除元素X
* @param x
*/
public void remove(AnyType x){
root = remove(x, root);
}
/**
* 打印树的所有元素,如果是空树则打印"is a empty tree"
*/
public void printTree(){
if(isEmpty()){
System.out.println("is a empty tree");
}else{
printTree(root);
}
}
/**
* 在树t中查找元素x
* @param x
* @param t
* @return boolean
*/
private boolean contains(AnyType x, BinaryNode<AnyType> t){
if(t == null){
return false;
}
int compareResult = x.compareTo(t.element);
if(compareResult<0){ //x如果比节点值小,继续查找左子树
return contains(x, t.left);
}else if(compareResult>0){ //x如果比节点值大,继续查找右子树
return contains(x, t.right);
}else{
return true;
}
}
/**
* 在树t中查找最小值
* @param t
* @return BinaryNode<AnyType>
*/
private BinaryNode<AnyType> findMin(BinaryNode<AnyType> t){
if(t == null){
return null;
}
if(t.left == null){ //不断遍历左子树,直到找到最小值,即没有左儿子的节点
return t;
}else{
return findMin(t.left);
}
}
/**
* 在树t中查找最大值
* @param t
* @return BinaryNode<AnyType>
*/
private BinaryNode<AnyType> findMax(BinaryNode<AnyType> t){
if(t == null){
return null;
}
if(t.right == null){ //不断遍历右子树,直到找到最大值,即没有右儿子的节点
return t;
}else{
return findMax(t.right);
}
}
/**
* 将元素x插入树t
* @param x
* @param t
* @return BinaryNode<AnyType>
*/
private BinaryNode<AnyType> insert(AnyType x, BinaryNode<AnyType> t){
if(t == null){
return new BinaryNode(x); //如果当前节点为空,则将新节点插入
}
int compareResult = x.compareTo(t.element);
if(compareResult<0){
return insert(x, t.left);
}else if(compareResult>0){
return insert(x, t.right);
}else{
return t;
}
}
/**
* 在树t中删除元素x
* @param x
* @param t
* @return BinaryNode<AnyType>
*/
private BinaryNode<AnyType> remove(AnyType x, BinaryNode<AnyType> t){
if(t == null){ //没有找到节点x
return t;
}
int compareResult = x.compareTo(t.element);
if(compareResult<0){
t = remove(x, t.left);
}else if(compareResult>0){
t = remove(x, t.right);
}else if(t.left!=null&&t.right!=null){ //找到节点且节点有两个儿子
t.element = findMin(t.right).element;
t.right = remove(t.element, t.right);
}else{ //找到节点且节点为树叶或只有一个儿子
t = (t.left != null)?t.left:t.right;
}
return t;
}
/**
* 打印树,顺序为先打印左儿子再打印根节点最后打印右儿子,从叶子节点开始打印
* @param t
*/
private void printTree(BinaryNode<AnyType> t){
if(t != null){
printTree(t.left);
System.out.println(t.element);
printTree(t.right);
}
}
/**
* 树的每一个节点元素,包含三个数据域,一个是当前节点值,一个是对左儿子的引用,一个是对右儿子的引用。
* @author Zhangxin
*
* @param <AnyType>
*/
private static class BinaryNode<AnyType>{
/**
* 初始节点,只设置节点值
* @param element
*/
public BinaryNode(AnyType element){
this(element, null, null);
}
/**
* 初始节点,包含节点值,左儿子引用,右儿子引用
* @param element
* @param left
* @param right
*/
public BinaryNode(AnyType element, BinaryNode<AnyType> left, BinaryNode<AnyType> right){
this.element = element;
this.left = left;
this.right = right;
}
AnyType element; //节点值
BinaryNode<AnyType> left; //左儿子引用
BinaryNode<AnyType> right; //右儿子引用
}
}