二叉查找树
二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree),亦称二叉搜索树。
定义
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的结点。
树的节点
二叉查找树要求所有的项都能排序,要写出一个一般的类,我们使用Comparable接口。
代码:
public class BinaryNode<T> {
T element;
BinaryNode<T> left;
BinaryNode<T> right;
BinaryNode(T element){
this(element,null,null);
}
BinaryNode(T element,BinaryNode<T> lt,BinaryNode<T> rt){
this.element=element;
this.left=lt;
this.right=rt;
}
}
BST树
代码:
public class BST<T extends Comparable<? super T>> {
private BinaryNode<T> root;
public boolean isEmpty(){
return root==null;
}
public boolean find(T x){//查询指定值的节点
return find(x,root);
}
public T findMin(){//查找最小节点的值
if(isEmpty())
throw new RuntimeException();
return findMin(root).element;
}
//同理查找最大
public void insert(T t){//插入
root=insert(t,root);
}
public void remove(T t){//删除
root=remove(t,root);
}
public boolean find(T x,BinaryNode<T> root){
//见查找
}
public BinaryNode<T> findMin(BinaryNode<T> root){
//见查找
}
public BinaryNode<T> insert(T t,BinaryNode<T> root){
//见插入
}
public BinaryNode<T> remove(T t,BinaryNode<T> root){
//见删除
}
}
查找
步骤:
否则,若小于根结点的关键字值,递归查左子树。
若大于根结点的关键字值,递归查右子树。
若子树为空,查找不成功。
最坏时间O(n)
平均O(logn)
平均:参考百度百科

最坏时间O(n)
平均O(logn)
平均:参考百度百科
在一般情况下,设 P(n,i)为它的左子树的结点个数为 i 时的平均查找长度。如图的结点个数为 n = 6 且 i = 3; 则 P(n,i)= P(6, 3) = [ 1+ ( P(3) + 1) * 3 + ( P(2) + 1) * 2 ] / 6= [ 1+ ( 5/3 + 1) * 3 + ( 3/2 + 1) * 2 ] / 6
注意:这里 P(3)、P(2) 是具有 3 个结点、2 个结点的二叉分类树的平均查找长度。 在一般情况,P(i)为具有 i 个结点二叉分类树的平均查找长度。
P(3) = (1+2+2)/ 3 = 5/3
P(2) = (1+2)/ 2 = 3/2∴ P(n,i)= [ 1+ ( P(i) + 1) * i + ( P(n-i-1) + 1) * (n-i-1) ] / n
∴ P(n)=
P(n,i)/ n <= 2(1+I/n)lnn
因为 2(1+I/n)lnn≈1.38logn 故P(n)=O(logn)
步骤:
代码:
查找最小:
public BinaryNode<T> findMin(BinaryNode<T> root){
if(root.left==null)
return root;
return findMin(root.left);
}
查找:
public boolean find(T x,BinaryNode<T> root){
if(root==null)
return false;
int result=x.compareTo(root.element);
if(result<0)
return find(x,root.left);
else if(result >0)
return find(x,root.right);
else
return true;
}
插入
步骤:
首先执行查找算法,找出被插结点的父亲结点。
若查到已知节点,则什么都不用做(或做一些更新)
若查到已知节点,则什么都不用做(或做一些更新)
判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
代码:
public BinaryNode<T> insert(T t,BinaryNode<T> root){
if(root==null)
return new BinaryNode<T>(t,null,null);
int result=t.compareTo(root.element);
if(result<0)
root.left=insert(t,root.left);
else if(result>0)
root.right=insert(t,root.right);
else
;//do nothing
return root;
}
删除
步骤
分三种情况:
1.若节点p为叶子节点,即左子树(PL)和右子树(PR)都为空时,直接删除。
2.若节点p只有左子树PL或者右子树(PL)时,只要让PL或PR直接成为父节点的左子树或右子树即可。
3.若节点p有左右两个子树,则用右子树最小的那个节点代替p节点,并递归的删除那个节点,
最坏时间:O(N)
平均时间:O(logn)
代码
public BinaryNode<T> remove(T t,BinaryNode<T> root){
if(root==null)
return null;
int result=t.compareTo(root.element);
if(result<0)
root.left=remove(t,root.left);
else if(result>0)
root.right=remove(t,root.right);
else if(root.left!=null&&root.right!=null){//两个子节点
root.element=findMin(root.right).element;//用右子树最小的节点替代当前节点
root.right=remove(root.element,root.right);//删除右子树最小节点
}
else{//只有一个节点或没有节点
return root.left==null?root.right:root.left;
}
return root;
}