您的位置:首页 > 理论基础 > 数据结构算法

Java数据结构之二叉搜索树

2016-08-30 18:56 141 查看

Java数据结构之二叉搜索树

1、二叉搜索树组成

二叉搜索树又称为二叉排序树,它或者是一颗空树,或者是一颗具有如下特性的非空二叉树,需要满足一下三个条件:
(1)若它的左子树非空,则左子树上所有结点的关键字均小于根结点的关键字;
(2)若它的右子树非空,则右子树上所有结点的关键字均大于(可以等于)根结点的关键字。
(3)左子树右子树本身又各是一颗二叉搜索树
在算法描述中,均以结点值的比较来代表其关键字的比较,因为若结点的值为类类型时,该类必须实现系统提供的java.lang.comparable接口并定义有compareTo成员方法,以便对对象进行比较。



二叉搜索树

2、二叉搜索树实现

对二叉搜索树的操作重要的有三个方法:1、插入一个结点;2、删除一个结点;3、查找是否存在一个结点;
该二叉搜索树是通过链式存储来实现的,首先定义结点:
//定义结点类型
class Node{
Object obj;
Node left;
Node right;
public Node(Object obj,Node left,Node right){
this.obj=obj;
this.left=left;
this.right=right;
}
}

1、插入一个结点

在二叉搜索树上进行插入结点操作时,要保证二叉搜索树的性质不变,即插入操作后二叉搜索树必须是按照左子树、根结点和右子树有序的。对二叉搜索树进行插入的过程是:首先需要查找新结点的插入位置,然后再插入链接。查找插入位置从树根结点开始,若树根指针为空,则新结点就是树根结点;否则,若obj等于根结点,则表明具有obj的值结点已经存在,不允许进行插入位置,应返回false表示插入失败;若obj小于根节点,则沿着根结点的左指针在左子树上继续查找插入位置,若obj大于根结点,则沿着根的右指针在右子树上继续查找插入位置。依次按层向下查找,当查找到一个结点的左指针或者是右指针为空时,则这个空的指针位置就是obj新结点的插入位置;
在进行插入链接时,若原树为空,则将新结点指针赋给boot,该新节点就成为整个二叉搜索树的树根结点,否则将新节点赋给pt结点的左指针域或者是右指针域,作为该结点的左孩子或是右孩子。插入完成后返回true。具体实现代码如下:
//插入一个元素,插入成功则返回true 失败则返回false
@Override
public boolean insert(Object obj) {
Node rt=root,pt=null;
while(rt!=null){
pt=rt;//把上一个结点给记录上
if((Integer)(rt.obj)>(Integer)obj){
rt=rt.left;
}else if((Integer)(rt.obj)<(Integer)obj){
rt=rt.right;
}else{
return false;
}
}
Node node=new Node(obj,null,null);//新建一个结点
if(pt==null){
root=node;
}else if((Integer)(pt.obj)<(Integer)obj){
pt.right=node;
}else{
pt.left=node;
}
return true;
}

2、查找一个结点

由于二叉搜索树的特殊性,查找过程可以表示为:若二叉搜索树为空,则表示查找失败,应返回null,否则,若obj等于当前树根结点的值,则表明查找成功,应返回结点的完整值,若obj小于当前树根结点的值,则继续同右子树的根结点比较。通过树根沿着左孩子或右孩子逐层向下比较,每比较一次,下移一层,当查找到取值为obj的结点时,表明查找成功,应返回该结点的值;或者查找到空指针值,表明查找失败,应返回null。实现代码如下:
//查找一个元素  找到则会返回该元素,找不到不会有任何返回
@Override
public Object find(Object obj) {
if(root==null) return null;
Node rt=root;
while(rt!=null){
if((Integer)(rt.obj)>(Integer)obj){
rt=rt.left;
}else if((Integer)(rt.obj)<(Integer)obj){
rt=rt.right;
}else{
return rt.obj;
}
}
return null;
}

3、删除一个结点

从二叉搜索树上删除结点(元素),它可能删除的是叶子结点,也可能删除的是分支结点,删除分支结点时,就破坏了原有结点之间的链接关系,需要重新修改指针,使得删除后仍为一颗二叉搜索树。
1、删除叶子结点
此种删除操作很简单,只要将其双亲结点链接到它的指针去掉即可。
2、删除单支结点
这种删除操作也比较简单,因为该结点只有左子树或右子树一支,也就是说,其伙计只有左孩子或右孩子一个。删除该节点时,只要将唯一的一个后继指针链接到它所在的链接位置即可。
3、删除双支结点
这种删除比较复杂,因为待删除的结点有两个后继指针,需要妥善处理,删除这种结点的一种方法是:首先将它的中序前驱的赋值给该结点的值域,然后再删除它的中序前驱结点,因它的中序前驱结点的右指针为空,所以只要把中序前驱结点的左指针连接到中序前驱结点所在的链接位置即可。
实现代码如下:
//从二叉搜索树中删除一个结点,分为三类
//1、删除叶子结点;2、删除单支结点;3、删除双支结点
@Override
public boolean delete(Object obj) {
//从二叉搜索树中删除等于给定值的obj的结点,成功则返回true,失败则返回false
if(root==null){
return false;
}
Node rt=root,pt=null;
while(rt!=null){
if((Integer)(rt.obj)==(Integer)obj){
break;
}else if((Integer)(rt.obj)>(Integer)obj){
pt=rt;
rt=rt.left;
}else {
pt=rt;
rt=rt.right;
}
}
if(rt==null) return false;//如果没找到该元素的话,返回空
//分三种情况删除以查找到的结点 rt
//删除叶子结点
if(rt.left==null && rt.right==null){//删除叶子结点,直接删除操作
if(rt==root) root=null;
else if(pt.left==rt) pt.left=null;
else pt.right=null;
}
//删除rt结点为单分支时的情况处理
else if(rt.left==null || rt.right==null){
if(rt==root){//先处理rt是根节点的情况
if(rt.left==null) root=rt.right;
else root=rt.left;
}else if(pt.left==rt && rt.left==null){//处理单支结点,分为四种情况
pt.left=rt.right;
}else if(pt.left==rt && rt.right==null){
pt.left=rt.left;
}else if(pt.right==rt && rt.left==null){
pt.right=rt.right;
}else if(pt.right==rt && rt.right==null){
pt.right=rt.left;
}else ;
}
//处理都有双子树的结点
else if(rt.left!=null && rt.right!=null){
Node s1=rt,s2=rt.left;
while(s2.right!=null){
s1=s2;s2=s2.right;
}
rt.obj=s2.obj;//把中序前驱结点s2的值赋给rt结点
if(s1==rt){//对rt的中序前驱结点就是rt的左孩子的情况进行处理
rt.left=s2.left;
}else{//对rt的中序前驱结点为其左海子的右子树的情况来处理
s1.right=s2.left;
}
}
return true;//删除成功后返回
}

输出搜索二叉树代码如下:
//输出二叉树
public void inOrderTravers(Node node){
if(node!=null){
inOrderTravers(node.left);
System.out.print(node.obj+" ");
inOrderTravers(node.right);
}else;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: