二叉查找树 Binary Search Tree
首先我们都知道树是一个基本的数据结构,他的组成有根节点以及孩子节点。树的大部分操作时间复杂度为O(log n)。
二叉树 Binary Tree
二叉树是树的一种特殊情况,他是只有左右两个孩子节点以及一个父亲节点的。如图所示
当然他也可以只有一个孩子节点。但是每个节点上的孩子节点最多也只有两个。所以我们称它为二叉树。
二叉查找树
也就是我们这篇文章所实现的,它是一种特殊的二叉树,使二叉树变成二叉查找树的性质是:对于每一个节点x,他的左子树的所有项的值都小于x中的项;而右子树中所有项的值都大于x中的项。
也就是说 对于节点 左子树的所有都要小于右子树的任意一个
如图所示
算法实现
首先二叉查找树要求所有的项都能够排序,所有我们用comparab这个接口。 创建一个匿名内部类,让他实现二叉树的基本结构,有孩子节点以及自己的数据,并用构造方法完成初始化操作。
初始化
public class MyBinarySearchTree<AnyType extends Comparable<? super AnyType>> {
private class BinaryNode<AnyType>{
private AnyType data;
private BinaryNode<AnyType> left;
private BinaryNode<AnyType> right;
public BinaryNode(AnyType data){this(data,null,null);}
private BinaryNode(AnyType data,BinaryNode<AnyType> left,BinaryNode<AnyType> right){
this.data=data;
this.left=left;
this.right=right;
}
}
BinaryNode<AnyType> root;
public MyBinarySearchTree(){doClear();} //初始化
public void clear(){doClear();}
private void doClear(){
root=null; //设置根节点为null
}
public boolean isEmpty(){return root==null;} //是否为空
public void makeEmpty(){root=null;} //相当于clear
是否包含
判断一个值是否包含在树当中,若存在返回true 反之false;
用compareTo进行内容的比较
若compareTo的结果大于0,则寻找当前节点的右子树进行继续比较。
若compareTo的结果小于0,则寻找当前节点的左子树进行继续比较。
直到等于0 为找到!则返回true
public boolean contains(AnyType x){return contains(x,root);} //给用户提供的接口 判断是否树中有该值
private boolean contains(AnyType x,BinaryNode<AnyType> node){
if(node==null)
return false;
int compareResult=x.compareTo(node.data);
if(compareResult>0)
return contains(x,node.right);
else if(compareResult<0)
return contains(x,node.left);
else
return true;
}
插入
insert为用户提供的插入方法,root根永远不变。根据compareTo进行比较,大于0往右走,小于0往左走。等于0不操作,即该数值在树中存在,最后返回当前节点。
好多人就会问为什么返回当前节点根节点不变呢?
因为我们的插入操作是使用递归实现的,当我们插入第一个值的时候,他就是根节点,第二个值的时候插入返回的是他的孩子节点,但我们看我们用的是root的孩子节点进行接收的,所以递归返回到最后root节点是不变的,还是第一次输入的那个值。
public void insert(AnyType x){root=insert(x,root);} //给用户提供的用于插入数据的方法,根节点始终为根不变
private BinaryNode<AnyType> insert(AnyType x,BinaryNode<AnyType> node){
if(node==null)
return new BinaryNode<>(x,null,null);
int compareResult=x.compareTo(node.data);
if(compareResult>0)
node.right=insert(x,node.right);
else if(compareResult<0)
node.left=insert(x,node.left);
else ; //若相等则不操作
return node;
}
删除操作
public void remove(AnyType x){root=remove(x,root);}
private BinaryNode<AnyType> remove(AnyType x,BinaryNode<AnyType> node){
if(isEmpty())
return node;
int compareResult=x.compareTo(node.data);
if(compareResult>0)
node.right=insert(x,node.right);
else if(compareResult<0)
node.left=insert(x,node.left);
else if(node.left!=null&&node.right!=null){ //当前节点的左右子树都存在的情况
node.data=findMin(node.right).data; //则把右子树最小的值作为将要去掉的节点的值
node.right=remove(node.data,node.right); //消除右子树最小的那个树的值,但是节点不消除
}
else
node=(node.left!=null)?node.left:node.right; //左右子树一方存在的情况,把存在的一方赋给去除的节点
return node;
}
寻找最大值最小值
public AnyType findMin(){return findMin(root).data;}
private BinaryNode<AnyType> findMin(BinaryNode<AnyType> node){
if(node==null)
return null;
else if(node.left==null) //如果左子树为空则找到了最小值
return node;
return findMin(node.left); //否则继续往左走
}
public AnyType findMax(){return findMax(root).data;}
private BinaryNode<AnyType> findMax(BinaryNode<AnyType> node){
if(isEmpty())
return null;
else if(node.right==null)
return node;
return findMax(node.right);
}
打印树
public void print(){
if(isEmpty())
System.out.println("Empty");
else
print(root);
} //提供打印树的方法 采用递归不停的打印
private void print(BinaryNode<AnyType> node){
if(node!=null) {
print(node.left);
System.out.println(node.data);
print(node.right);
}
}
}
测试
public class testTree {
public static void main(String[] args) {
MyBinarySearchTree<Integer> boo=new MyBinarySearchTree();
boo.insert(6);
boo.insert(8);
boo.insert(3);
boo.insert(9);
boo.print();
}
}