参考:数据结构与算法分析——Java语言描述 (美)Mark Allen Weis
我们都知道,二叉树中每个节点都不能有多于两个的儿子。要使二叉树成为二叉查找树,要满足这样的性质:对于树中的每个节点x,它的左子树中的所有项的值小于x中的项,而它的右子树中的所有项的值大于x中的项。
上面的这个性质的说明,没有明显地指出值相等的元素的情况。当然可以把重复的元插入树中,上面的性质“小于”就可以改成“小于等于”,或者“大于”改成“大于等于”。不过把重复的信息放入树中并不好,因为它将会使树的深度变得很大。我们可以在树节点中增加一个域,用来表明数据出现的次数。二叉查找树的节点类如下:
TreeNode:
package com.BST;
public class TreeNode {
int element; //节点存放的数据
int num; //element出现的次数
TreeNode left;
TreeNode right;
public TreeNode(int element,TreeNode l,TreeNode r){
this.element=element;
num=1;
left=l;
right=r;
}
}
我们可以写这样一个二叉查找树类 BinarySeachTree ,其中包括这样几种主要操作。
1.查找最小值 findMin(TreeNode t) 和 查找最大值 findMax(TreeNode t)
这两个操作很简单。返回树中包含最小元和最大元的节点的引用。以 findMin 为例,从根开始,只要有左儿子就向左进行。findMax操作则相反。
2.查找某个元素 find(TreeNode t,int target)
返回树 t 中含有项 target 的节点的引用,如果这样的节点不存在则返回 null 。如果 t 是空,那么返回 null 。否则,如果存储在 t 中的项是 target ,那么返回 t 。否则,对树的左子树或右子树进行一次递归调用,这取决于 target 与 t 中的数的大小关系。
3.插入 insert(TreeNode t,int data)
设要插入的数据是 data ,如果 data<t.element ,那么就把 data 插入到树 t 的左子树中,反之,插入到右子树中。 如果相等,那么t.num++ 。
4.删除 remove(TreeNode t,int data)
删除操作比较困难。一旦发现要被删除的节点,需要考虑几种可能的情况。如果节点是一片树叶,那么它可以立刻被删除(如果它是重复元素的话,就是指将它的num-1,后面涉及到删除时也是同样的道理)。如果节点有一个儿子,则节点可以在其父亲节点调整它的链以绕过该节点后被删除。如果是具有两个儿子的节点,一般的删除策略是用其右子树的最小的数据代替该节点的数据并递归地删除那个节点。
5.遍历 print(TreeNode t)
我们这里的遍历指把所有数据打印出来。只要通过简单的递归就可以了。只要 t 不为空,先打印左子树,然后打印节点数据,最后打印右子树即可。
BinarySearchTree:
package com.BST;
public class BinarySearchTree {
TreeNode root; //根节点
/**
* 构造二叉查找树
*/
public BinarySearchTree(){
root=null;
}
/**
* 使为空
*/
public void makeEmpty(){
root=null;
}
/**
* 查找最小值
*/
public int findMin(){
return elementAt( findMin(root) );
}
/**
* 查找最大值
*/
public int findMax(){
return elementAt( findMax(root) );
}
/**
* 查找
*/
public TreeNode find(int target){
return find(root, target);
}
/**
* @param data 要插入的数据
*/
public void insert(int data){
root=insert(root, data);
}
/**
*
* @param data 要删除的数据
*/
public void remove(int data){
root=remove(root, data);
}
/**
* 遍历二叉查找树
*/
public void print(){
print(root);
System.out.println();
}
//查找最小值
private TreeNode findMin(TreeNode t){
if(t!=null)
while(t.left!=null)
t=t.left;
return t;
}
//查找最大值
private TreeNode findMax(TreeNode t){
if(t!=null)
while(t.right!=null)
t=t.right;
return t;
}
//查找
private TreeNode find(TreeNode t,int target){
if(t==null)
return null;
if(t.element<target)
return find(t.right,target);
else if(t.element>target)
return find(t.left,target);
else
return t;
}
//插入
private TreeNode insert(TreeNode t,int data){
if(t==null)
t=new TreeNode(data,null,null);
else{
if(data<t.element)
t.left=insert(t.left, data);
else if(data>t.element)
t.right=insert(t.right, data);
else
t.num++;
}
return t;
}
//删除
private TreeNode remove(TreeNode t,int data){
if(t==null)
return null;
if(data<t.element)
t.left=remove(t.left, data);
else if(data>t.element)
t.right=remove(t.right, data);
else if(t.left!=null && t.right!=null){
t.num--;
if(t.num<=0){
TreeNode rightMInNode=findMin(t.right);
t.element=rightMInNode.element;
t.num=rightMInNode.num;
rightMInNode.num=1;
t.right=remove(t.right,t.element);
}
}else{
t.num--;
if(t.num<=0)
{
t=(t.left!=null)? t.left:t.right;
}
}
return t;
}
//遍历
private void print(TreeNode t){
if(t!=null)
{
print(t.left);
for(int i=1;i<=t.num;i++)
System.out.print(t.element+" ");
print(t.right);
}
}
//elementAt
private int elementAt(TreeNode t)
{
return (t==null)? null:t.element;
}
}
Main:
package com.BST;
public class Main {
public static void main(String[] args) {
BinarySearchTree bst=new BinarySearchTree();
bst.insert(1);
bst.insert(8);
bst.insert(6);
bst.insert(2);
bst.insert(3);
bst.insert(56);
bst.insert(4);
bst.insert(4);
bst.print();
bst.insert(3);
bst.print();
bst.remove(3);
bst.print();
bst.remove(6);
bst.print();
System.out.println("最小值:"+bst.findMin());
System.out.println("最大值:"+bst.findMax());
int target=4;
System.out.println("找"+target);
TreeNode t=bst.find(target);
if(t!=null){
System.out.println("找到!"+target+"出现"+t.num+"次!");
}else
System.out.println("没找到!");
}
}
运行结果:
1 2 3 4 4 6 8 56
1 2 3 3 4 4 6 8 56
1 2 3 4 4 6 8 56
1 2 3 4 4 8 56
最小值:1
最大值:56
找4
找到!4出现2次!