查找——查找树

基于树的查找方法是将待查表组织成特定的树结构,并在树结构的基础上实现查找的方法。


1.二叉查找树

这里写图片描述
这里写图片描述

1.1 查找算法

基本查找方法是从根结点开始,递归的缩小查找范围,直到发现目标元素为止(查找成功)或查找范围缩小为空树(查找失败)。

基本思想是:
若查找树不为空,将待查关键字与根节点元素进行比较——> 若相等直接返回根结点——> 否则判断待查关键字与根结点的大小——> 如果待查关键字小,则递归在左子树查找——>否则在右子树查找

这里写图片描述

/**
 * 
 * 二叉查找树 —— 递归形式
 */
public Node search(Object ele){
    return binTSearchRe(root,ele);
}
private Node binTSearchRe(BinTreeNode rt, Object ele) {
    if(rt == null){
        return null;
    }
    switch (strategy.compare(ele,rt.getData())) {
        case 0:
            return rt;
        case -1:
            return binTSearchRe(rt.getLChild(), ele);//小于
        case 1:
            return binTSearchRe(rt.getRChild(), ele);
    }
    return null;
}
/**
 * 二叉查找树——非递归形式
 */
private Node binTSearch(BinTreeNode rt, Object ele) {
    while(rt != null){
        switch (strategy.compare(ele,rt.getData())) {
        case 0:
            return rt;
        case -1:
            rt = rt.getLChild();//小于
            break;
        case 1:
            rt = rt.getRChild();
            break;
        }
    }
    return null;
}

1.2 最大最小值

在二叉查找树中,最小元素总是能够通过根结点向左不断深入,直到到达最左的一个叶子结点找到;而最大元素总是能够通过根结点向右不断深入,直到到达最右的一个叶子结点找到。

这里写图片描述

public Node min(BinTreeNode v){
    if(v != null){
        while(v.hasLChild()){
            v = v.getLChild();
        }
    }
    return v;
}

public Node max(BinTreeNode v) {
    if(v != null){
        while(v.hasRChild()){
            v = v.getRChild();
        }
    }
    return v;
}

1.3 前驱和后继

基本思想

  • 如果结点v有右子树,那么v的后续结点是v的右子树中关键字最小的
  • 如果V右子树为空,并且b的后续结点存在,那么v的后续结点是从v到根的路径上第一个作为左孩子结点的父结点。

/**
 * 获得后续结点
 * @param v 根结点
 * @return v在中序遍历序列中的后续结点
 */
private BinTreeNode getSuccessor(BinTreeNode v) {
    if(v == null){
        return null;
    }
    if(v.hasRChild()){
        return (BinTreeNode) min(v.getRChild());
    }
    while(v.isRChild()){//如果最小的值是右结点,后继应该是其父结点--中序遍历顺序是 左父右
        v = v.getParent();
    }
    return v.getParent();
}

/**
 * 获得前驱结点
 * @param v 根结点
 * @return v在中序遍历序列中的后续结点
 */
private BinTreeNode getPredecessor(BinTreeNode v) {
    if(v == null){
        return null;
    }
    if(v.hasLChild()){
        return (BinTreeNode) max(v.getRChild());
    }
    while(v.isLChild()){//如果最小的值是右结点,后继应该是其父结点--中序遍历顺序是 左父右
        v = v.getParent();
    }
    return v.getParent();
}

1.4 插入算法

这里写图片描述

/**
 * 
 * @param ele 待插元素
 */
public void insert(Object ele){
    BinTreeNode p = null;
    BinTreeNode current = root;
    while(current != null){
        p = current;
        if(strategy.compare(ele, current.getData()) < 0){
            current = current.getLChild();
        }else{
            current = current.getRChild();
        }
    }

//  startBN = p;//待平衡出发点

    if(p == null){
        root = new BinTreeNode(ele);//树为空
    }else if(strategy.compare(ele, p.getData()) < 0){
        p.setLChild(new BinTreeNode(ele));
    }else{
        p.setRChild(new BinTreeNode(ele));
    }

}

1.5 删除算法

这里写图片描述
这里写图片描述
这里写图片描述

  • 如果是叶子结点,直接删除
  • 如果只有一个子树时,v直接替换为这一个子树值
  • 有两棵树,要保证中序遍历的有序性,先用v的前驱或后继替换v,然后删除其前驱或后继结点即可,然后按照之前规则继续
/**
 * 
 * @param ele 待删除元素
 * @return
 */
public Object remove(Object ele) {
    BinTreeNode v = (BinTreeNode) binTSearch(root, ele);
    if(v == null){
        return null;
    }
    BinTreeNode del = null;//待删结点
    BinTreeNode subT = null;//待删结点的子树
    if(!v.hasLChild() || !v.hasRChild()){//确定待删结点
        del = v;
    }else{
        del = getPredecessor(v);
        Object old = v.getData();
        v.setData(del.getData());
        del.setData(old);
    }

//  startBN = del.getParent();//待平衡出发点

    //此时待删结点只有左子树或右子树
    if(del.hasLChild()){
        subT = del.getLChild();
    }else{
        subT = del.getRChild();
    }

    //若待删结点为根
    if(del == root){
        if(subT != null){
            subT.sever();
        }
        root = subT;
    }else if(subT != null){
        //del为非叶子结点
        if(del.isLChild()){
            del.getParent().setLChild(subT);
        }else{
            del.getParent().setRChild(subT);
        }
    }else{
        //del为叶子结点
        del.sever();
    }
    return del.getData();
}

2.AVL树

这里写图片描述

2.1 旋转操作

这里写图片描述
这里写图片描述
这里写图片描述

2.2 失去平衡后的重新平衡

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

2.3 旋转操作的统一实现方法

这里写图片描述
这里写图片描述

/**
 * rotate
 * @param z 失衡的结点
 * @return 平衡后子树的根节点
 */
private BinTreeNode rotate(BinTreeNode z) {
    BinTreeNode y = higherSubT(z);//取y为z更高的孩子
    BinTreeNode x = higherSubT(y);//取x为y更高的孩子
    boolean isLeft = z.isLChild();//记录:z是否左孩子
    BinTreeNode p = z.getParent();//p为z的父亲
    BinTreeNode a,b,c;//自左向右,三个结点
    BinTreeNode t0,t1,t2,t3;//自左向右,四棵子树

    //以下分四种情况重命名
    if(y.isLChild()){//若y是左孩子
        c = z;
        t3 = z.getRChild();
        if(x.isLChild()){//若x是左孩子(左左失衡)
            b = y;
            t2 = y.getRChild();
            a = x;
            t1 = x.getRChild();
            t0 = x.getLChild();
        }else{//若x是左孩子(左右失衡)
            a = y;
            t0 = y.getLChild();
            b = x;
            t1 = x.getLChild();
            t2 = x.getRChild();
        }
    }else{//若y是右孩子
        a = z;
        t0 = z.getLChild();
        if(x.isRChild()){//若x是右孩子(右右失衡)
            b = y;
            t1 = y.getLChild();
            c = x;
            t2 = x.getLChild();
            t3 = x.getRChild();
        }else{//若x是右孩子(右左失衡)
            c = y;
            t3 = y.getRChild();
            b = x;
            t1 = x.getLChild();
            t2 = x.getRChild();
        }
    }

    //摘下三个结点
    z.sever();
    y.sever();
    x.sever();

    //摘下四棵子树
    if(t0 != null){
        t0.sever();
    }
    if(t1 != null){
        t1.sever();
    }
    if(t2 != null){
        t2.sever();
    }
    if(t3 != null){
        t3.sever();
    }

    //重新链接
    a.setLChild(t0);
    a.setRChild(t1);
    c.setLChild(t2);
    c.setRChild(t3);
    b.setLChild(a);
    b.setRChild(c);

    //子树重新接入原树
    if(p != null){
        if(isLeft){
            p.setLChild(b);
        }else{
            p.setRChild(b);
        }
    }
    return b;//返回新的子树根

}

//返回结点v较高的子树
private BinTreeNode higherSubT(BinTreeNode v) {
    if(v == null){
        return null;
    }
    int lH = (v.hasLChild()) ? v.getLChild().getHeight() : -1;
    int rH = (v.hasRChild()) ? v.getRChild().getHeight() : -1;
    if(lH > rH){
        return v.getLChild();
    }
    if(lH < rH){
        return v.getRChild();
    }
    if(v.isLChild()){
        return v.getLChild();
    }else{
        return v.getRChild();
    }
}

2.4 AVL树的Java实现

这里写图片描述

/**
 * 
 * @param ele 待插元素
 */
public void insertAVL(Object ele){
    insert(ele);//调用插入方法
    root = reBalance(startBN);
}
//从v开始重新平衡AVL树
private BinTreeNode reBalance(BinTreeNode v) {
    if(v == null){
        return root;
    }
    BinTreeNode c = v;
    while(v != null){//从v开始,向上逐一检查z的祖先
        if(!isBalance(v)){//若V失衡,则旋转使之重新平衡
            v = rotate(v);
        }
        c = v;
        v = v.getParent();//继续检查其父亲
    }
    return c;
}
//判断一个结点是否失衡
private boolean isBalance(BinTreeNode v) {
    if(v == null){
        return true;
    }
    int lH = (v.hasLChild())?v.getLChild().getHeight():-1;
    int rH = (v.hasRChild())?v.getRChild().getHeight():-1;
    return (Math.abs(lH-rH) <= 1);
}
/**
 * 
 * @param ele 待删元素
 * @return
 */
public Object removeAVL(Object ele) {
    Object obj = remove(ele);
    root = reBalance(startBN);
    return obj;
}

3.B-树

这里写图片描述
这里写图片描述

3.1 查找

这里写图片描述
这里写图片描述

3.2 关键字的插入操作

这里写图片描述
这里写图片描述
这里写图片描述

3.3 关键字的删除操作

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值