二叉排序树的插入和删除操作

简介: 二叉排序树的插入和删除操作

公众号merlinsea


  • 二叉排序树介绍
  • 二叉排序树是一棵二叉树或者空树
  • 若它的左子树不空,则左子树的所有节点的关键字均小于根节点
  • 若它的右子树不空,则右子树的所有节点的关键字均大于根节点

640.png

  • 二叉排序树的插入操作
  • 插入操作是指向一个二叉排序树中插入一个元素,如果这个元素已经存在,则插入失败;如果不存在则插入成功。
  • 插入操作结束后仍旧需要保证这个二叉排序树的左小右大的特点。
  • 比如向上面这个二叉排序树中插入元素6,这个元素6最后会插入在节点5的右孩子处。

  • 插入操作——代码实现


/ 返回true代表插入成功,返回false代表插入失败
    public boolean insert(BTNode p){
        if(p==null){
            return false;
        }
        if(root==null){
            root = p;
        }else{
            //工作节点
            BTNode work = root;
            while(work!=null){
                if(work.val < p.val){
                    //p应该插入在work的右边
                    if(work.right!=null){
                        work = work.right;
                    }else{
                        //完成了插入;
                        work.right = p;
                        break;
                    }
                }else if(work.val > p.val){
                    //p应该插入在work的左边
                    if(work.left != null){
                        work = work.left;
                    }else{
                        //完成插入插入操作
                        work.left = p;
                        break;
                    }
                }else{
                    //我们找到了一个一抹一样的节点,更新info信息,返回fasle
                    work.info = p.info;
                    return false;
                }
            }
        }
        return true;
    }


  • 二叉排序树的查询操作
  • 查询操作就是从树的根节点出发,查找知道关键值的元素,如果可以找到则返回这个元素,如果不可以找到则返回空。
  • 查询操作的代码实现


public BTNode find(int val){
        BTNode p = root;
        while(p!=null){
            if(p.val == val){
                break;
            }else if(p.val < val){
                //说明目标节点在p的右边
                p = p.right;
            }else{
                //说明目标节点在p的左边
                p = p.left;
            }
        }
        return p;
    }


  • 二叉排序树的删除操作
  • 删除操作是指需要在一棵二叉排序树中删除指定关键字的节点,同样的删除以后需要保证二叉排序树的左小右大的特征。
  • 二叉排序树删除的三种情况
  • 删除的是叶子节点,即待删除元素左右子树都为空的情况,直接删除即可。
  • 删除的是单分支的节点,即待删除元素左子树为空右子树不为空 或者 右子树为空左子树不为空,只需要讲其孩子节点来替代这个待删除的节点即可。
  • 删除的是双分支节点,即待删除的元素左右子树都不空的情况,可以将其左子树中的最大值来替换当前节点,同时删除左子树中的最大值,或者可以将其右子树中的最小值来替换当前节点,同时删除右子树中的最小值。
  • 删除节点的时候,我们需要找到待删除目标节点的父节点,比如下图中我们需要删除节点4,我们需要找到4的父节点5,让5的左指针指向2。

640.png


  • 删除操作代码实现


public boolean delete(int val){
        //1、先找到待删除元素的父节点
        BTNode target = findDel(val);
        if(target==null){
            // 说明查找失败
            return false;
        }
        //2、删除元素 ---> 根节点 / 非根节点
        //左子树的最大值来填充
        if(val == root.val){
            //说明删除的是根节点
            if(root.left == null && root.right ==null){
                root = null;
            }else if(root.left == null){
                root = root.right;
            }else if(root.right == null){
                root = root.left;
            }else{
                //寻找左子树最大值
                BTNode p = root.left;
                while(p.right != null){
                    p = p.right;
                }
                delete(p.val);
                root.val = p.val;
                root.info = p.info;
            }
        }else{
            //说明删除的不是根节点,则target是待删除元素的父亲节点
            if(target.left!=null && target.left.val == val){
                //说明需要删除的是target的左节点
                BTNode del = target.left;
                if(del.left == null && del.right == null){
                    target.left = null;
                }else if(del.left == null){
                    target.left = del.right;
                }else if(del.right == null){
                    target.left = del.left;
                }else{
                    //说明待删除元素有左右孩子节点
                    BTNode p = del.left;
                    while(p.right!=null){
                        p = p.right;
                    }
                    delete(p.val);
                    del.val = p.val;
                    del.info = p.info;
                }
            }else{
                //说明待删除的是target的右孩子
                BTNode del = target.right;
                if(del.left == null && del.right == null){
                    target.right = null;
                }else if(del.left == null){
                    target.right = del.right;
                }else if(del.right == null){
                    target.right = del.left;
                }else{
                    //说明待删除元素有左右孩子节点
                    BTNode p = del.left;
                    while(p.right!=null){
                        p = p.right;
                    }
                    delete(p.val);
                    del.val = p.val;
                    del.info = p.info;
                }
            }
        }
        return true;
    }
    //找的是val的父节点
    public BTNode findDel(int val){
        if(root==null){
            return null;
        }
        if(val == root.val){
            return root;
        }
        BTNode p = root;
        while(p!=null){
            if(val < p.val){
                if(p.left != null && p.left.val == val){
                    return p;
                }else if(p.left == null){
                    return null;
                }else{
                    //存在但不相等
                    p = p.left;
                }
            }else{
                if(p.right !=null && p.right.val == val){
                    return p;
                }else if(p.right == null){
                    return null;
                }else{
                    p = p.right;
                }
            }
        }
        return null;
    }


  • 二叉排序树的不足
  • 假设我们需要建立一棵二叉排序树,但我们依次插入的元素是[1,2,3,4,5,6,7,8,9),那么我们实际插入的树其实以一颗只有右子树,没有左子树的树。那么其查找效率会退化为一个单链表。



相关文章
|
移动开发 vr&ar
数据库系统概论——关系代数详解
关系代数是一种抽象的查询语言,是关系数据操纵语言的一种传统表达方式,它是利用对关系的运算来表达查询的。任何运算都是将一定的运算符作用于一定的运算对象上,得到预期的运算结果。关系代数的运算对象是关系,运算结果亦为关系。集合运算符将关系看成元组的集合从关系的“水平”方向即行的角度来进行运算专门的关系运算符不仅涉及行而且涉及列算术比较符辅助专门的关系运算符进行操作逻辑运算符辅助专门的关系运算符进行操作。
2912 1
数据库系统概论——关系代数详解
|
存储 持续交付 云计算
云计算——云计算关键技术
云计算——云计算关键技术
5564 0
|
机器学习/深度学习 算法 前端开发
阿里面试官分享+真实面经+笔试模拟题 | 面试充电,就看这篇
阿里面试官分享+真实面经+笔试模拟题+招聘信息汇总,太全了!这篇合辑一定要看,不然就亏大啦!
阿里面试官分享+真实面经+笔试模拟题 | 面试充电,就看这篇
|
10月前
|
安全 C++ Windows
使用教程!Geek UninstallerV1.5.3.170 深度卸载神器完全使用指南!彻底告别软件残留
Geek Uninstaller是一款免费、轻量级的深度卸载工具,能彻底清除软件残留文件和注册表项,解决系统卡慢、空间占用等问题。支持普通卸载、强制卸载及Windows预装应用清理,操作简单,无需安装,一键释放硬盘空间,提升系统性能。
3532 8
|
算法
虚拟内存的页面置换算法有哪些?
【10月更文挑战第25天】不同的页面置换算法各有优缺点,在实际应用中,操作系统会根据不同的应用场景和系统需求选择合适的页面置换算法,或者对算法进行适当的改进和优化,以平衡系统的性能、开销和资源利用率等因素。
1085 141
计算机组成原理(6)-----指令执行过程
计算机组成原理(6)-----指令执行过程
2555 0
|
存储 算法 数据管理
数据结构与算法学习二零:二叉排序树(BST)、平衡二叉树(AVL)
这篇文章通过需求分析、代码实现和测试验证,详细介绍了二叉排序树的创建、遍历和删除操作,以及二叉平衡树(AVL)的自平衡特性和单旋转操作,旨在提高树结构在数据管理中的效率和性能。
728 0
数据结构与算法学习二零:二叉排序树(BST)、平衡二叉树(AVL)
|
SQL 存储 关系型数据库
详解 SQL 中的 UNION、MINUS 和 INTERSECT 命令
【8月更文挑战第31天】
1578 0
|
机器学习/深度学习 算法 安全
【博士每天一篇文献-综述】2024机器遗忘最新综述之一:An overview of machine unlearning
本文提供了机器遗忘的全面定义、问题方程、精确与近似遗忘的概念,并分类总结了机器遗忘方法,讨论了其在联邦学习和终身学习中的应用,提出了未来研究方向,为机器遗忘研究领域奠定了理论基础并指出了实际应用的潜力与挑战。
1633 5
【博士每天一篇文献-综述】2024机器遗忘最新综述之一:An overview of machine unlearning
408数据结构学习笔记——二叉排序树、二叉平衡树、红黑树
408数据结构学习笔记——二叉排序树、二叉平衡树、红黑树
1331 1
408数据结构学习笔记——二叉排序树、二叉平衡树、红黑树