二叉搜索树

完整实例的GitHub地址

https://github.com/lvxixiao/DSA

顺序性

任一节点r的左(右)子树中,所有节点均小于(大于)r。

中序遍历序列

任何一棵二叉搜索树,其中序遍历序列单调非降。

查找算法及其实现

二叉搜索树的查找算法,采用减而治之的思路与策略,其执行过程可以描述为:从树根触发,逐步地缩小查找范围,直到发现目标(成功)或缩小至空树(失败)

public BinNode<T> search(T e) {
        return searchIn(root,e);
}
private BinNode<T> searchIn(BinNode<T> v, T e) {
    if(v==null || v.getData()==e)//递归基,假想在节点v处命中
        return v;
    this.hot = v;
    return v.getData().compareTo(e)<0?searchIn(v.getRc(), e):searchIn(v.getLc(),e);
}//返回时,返回值指向命中节点,hot指向其父亲。

插入算法及其实现

为了在二叉搜索树中插入一个节点,首先需要利用查找算法确定插入的位置及方向,然后才能将新节点作为叶子插入。

首先调用search()查找e。若返回位置x非空,则说明已有雷同节点,插入失败。否则x必是hot节点的某一空孩子,于是创建这个孩子并存入e。

//插入
public boolean insert(T e) {
    BinNode<T> x = search(e);
    //默认不存在重复元素
    if(x!=null) 
        return false;
    //创建新节点,search(e)后确定的hot为其父亲。
    x = new BinNode<T>(e,this.hot, null, null);
    if(this.hot.getData().compareTo(e) < 0) {
        this.hot.setRc(x);
    } else {
        this.hot.setLc(x);
    }
    return true;
}

删除算法及其实现

为从二叉搜索树中删除节点,首先需要调用搜索算法,判断目标节点是否存在于树中,若存在,则需返回其位置,然后相应的实施删除操作。

单分支情况

对于待删除节点仅仅拥有左孩子的情况,只需要将其替换为左孩子,然后令其左孩子为Null,删除操作便完成了。对称的仅有右孩子的情况,操作类似。

双分支情况。

对于左右孩子都存在的情况,需要找到该节点的直接后继,然后只需要交换二者的数据项,则可将后继节点等效视作待删除的目标节点。

删除算法代码

    //删除
    public boolean remove(T e) {
        BinNode<T> x = search(e);
        if(x==null)
            return false;
        removeAt(x);
        return true;
    }
    private void removeAt(BinNode<T> x) {
        BinNode<T> w = x;//实际被摘除的节点,初值等于x
        BinNode<T> succ = null;//实际被删除节点的接替者
        boolean isLeftChild = true;//用来确定待删除节点是父亲节点的左孩子还是右孩子        

        if( !x.hasLChild() )//如果左子树为空
        {
            succ = x.getRc();
            x = x.getRc();
        } else if(!x.hasRChild()){ //如果右子树为空
            succ = x.getLc();
            x = x.getLc();
        } else { //左右子树都存在
            w = w.succ();
            swap(x,w);
            BinNode<T> u = w.getParent();
            succ = w.getRc();
            if(u==x) {
                u.setRc(succ);
            } else {
                u.setLc(succ);
            }
        }
        this.hot = w.getParent();
        if(hot!=null) {
            if(hot.getData().compareTo(w.getData())<0) {
                isLeftChild=false;
            } else {
                isLeftChild=true;
            }
            //判断是否有接替者
            if(succ!=null) {
                //建立双向连接,隔离被删除节点
                if(isLeftChild) {
                    hot.setLc(succ);                    
                } else {
                    hot.setRc(succ);
                }
                succ.setParent(hot);
            } else {
                if(isLeftChild) {
                    hot.removeLc();
                } else {
                    hot.removeRc();
                }
            }
        } 
    }

public class BinNode<T extends Comparable<T>> {
    private T data;
    private BinNode<T> parent;
    private BinNode<T> lc;
    private BinNode<T> rc;  
    //取当前节点的直接后继
    public BinNode<T> succ() {
        BinNode<T> s = this;
        //如果有右孩子,直接后继必在右子树中最靠左的节点
        if(s.getRc()!=null) {
            s = getRc();
            while(s.hasLChild())
                s = s.getLc();
        } else {
            //如果没有右孩子,直接后继位于“将当前节点包含于其左子树中的最低祖先”
            while(s.isRChild())
                s = s.getParent();
            s = s.getParent();
        }
        return s;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值