查找树ADT-二叉查找树
二叉树的一个重要的应用就是它们在查找中的使用。假如树种每个节点存储一项数据,且无重复元素的情况。
二叉查找树要求所有项都能够排序。要写出一个一般类,我们需要提供interface来表示这个性质,这个接口就是Comparable。
private static class BinaryNode<Integer>{
public BinaryNode(Integer data){
this(data,null,null);
}
BinaryNode(Integer data,BinaryNode<Integer> lt,BinaryNode<Integer> rt){
this.data=data;
this.left=lt;
this.right=rt;
}
Integer data;
BinaryNode<Integer> left;//左结点
BinaryNode<Integer> right;//右结点
}
其中唯一的数据域是对根节点的引用,这个引用对于空树来说是null,这些public方法使用了调用诸private递归方法的一般技巧。
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
/**
* 定义树结点
* @param <Integer>
*/
private static class BinaryNode<Integer>{
public BinaryNode(Integer data){
this(data,null,null);
}
BinaryNode(Integer data,BinaryNode<Integer> lt,BinaryNode<Integer> rt){
this.data=data;
this.left=lt;
this.right=rt;
}
Integer data;
BinaryNode<Integer> left;//左结点
BinaryNode<Integer> right;//右结点
}
private Queue<BinaryNode<Integer>> queue;
private BinaryNode<Integer> root;
public BinarySearchTree(){
root=null;
}
public void makeEmpty(){
root=null;
}
public boolean isEmpty(){
return root==null;
}
public boolean contains(Integer data){
return contains(data,root);
}
public Integer findMin(){
if (isEmpty())throw new BufferUnderflowException();{
return findMin(root).data;
}
}
public Integer findMax(){
if (isEmpty()) throw new BufferUnderflowException();{
return findMax(root).data;
}
}
public void insert(Integer data){
root =insert(data,root);
}
public void insert(List<Integer> list){
for (Integer data: list) {
root=insert(data,root);
}
}
public void remove(Integer data){
root =remove(data,root);
}
public void printTree(){
if (isEmpty()) {
System.out.println("Empty tree");
}else{
printTree(root);
}
}
private boolean contains(Integer data, BinaryNode<Integer> t){
if (t==null) {
return false;
}
int compareResult=data.compareTo(t.data);
if(compareResult<0)
return contains(data,t.left);
else if(compareResult>0)
return contains(data,t.right);
else
return true;
}
private BinaryNode<Integer> findMin(BinaryNode<Integer> t){
if (t==null) {
return null;
}else if(t.left==null){
return t;
}
return findMin(t.left);
}
private BinaryNode<Integer> findMax(BinaryNode<Integer> t){
if (t!=null) {
while (t.right != null) {
t=t.right;
}
}
return t;
}
private BinaryNode<Integer> insert(Integer data,BinaryNode<Integer>t){
if (t==null) {
return new BinaryNode<>(data,null,null);
}
int compareResult=data.compareTo(t.data);
if (compareResult<0){
t.left=insert(data,t.left);
}else if(compareResult>0){
t.right=insert(data,t.right);
}else;
return t;
}
private BinaryNode<Integer> remove(Integer data,BinaryNode<Integer> t){
if (t==null) {
return t;
}
int compareResult=data.compareTo(t.data);
if (compareResult<0){
t.left=remove(data,t.left);
}else if(compareResult>0){
t.right=remove(data,t.right);
}else if(t.left!=null&&t.right!=null){
t.data=findMin(t.right).data;
t.right=remove(t.data,t.right);
}else {
t = (t.left != null) ? t.left : t.right;
}
return t;
}
private void printTree(BinaryNode<Integer> t){
if (t!=null) {
printTree(t.left);
System.out.println(t.data);
printTree(t.right);
}
}
}
一、 contains方法
如果在树T中存在含有项X的节点,那么这个操作需要返回true,如果这样的节点不存在,则返回false。
树的结构使得这种操作很简单,如果T是空集,那么可以就返回false.否则,如果存储在T处的项是X,那么可以返回true。
否则,我们对树T的左子树或者右子树进行一次递归调用,这依赖于X与存储在T中项的关系。
二、findMin方法和findMax方法
这两个private分别返回树种包含最小元和最大元的节点的引用,为执行findMin,从根开始并且只要有左儿子,就向左进行。终止点就是醉笑的元素。
findMax除分支朝向右儿子外其余过程相同。
这种递归是如此容易以至于许多程序设计员不厌其烦的是同它,我们用两种方法实现了这两种Method。用递归写了findMin,用非递归写了findMax。
三、insert方法
这个插入操作在概念上是简单的,为了将X插入到树T中,你可以用contains那样沿着树查找,如果找到了X,则什么也不用做,或者做一些更新,否则,将X插入到遍历路径上的最后一点上。
四、remove方法
正如许多数据结构一样,最困难的是remove。一旦我们发现要被删除的节点,就需要考虑几种情况。
如果节点是一片树叶,那么它可以被立即删除,如果节点有一个儿子,则该节点可以再其父节点调整自己的链以绕过该节点后被删除。
复杂的情况是处理具有两个儿子的节点,一般的删除策略是用其右子树的最小的数据代替该节点的数据并递归删除那个节点,因为右子树中的最小的节点不可能有左儿子,所以第二次remove要容易。