当前位置: 首页 > article >正文

数据结构-二叉搜索树(Java语言)

目录

1.概念

2.查找search

3.插入insert

​编辑4.删除remove(难点)

5.性能分析



1.概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 :
1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
3.它的左右子树也分别为二叉搜索树

比如:

二叉搜索树的基本属性和方法如下:

public class BinarySearchTree {
    class TreeNode{
        TreeNode left;
        TreeNode right;
        int val;
        public TreeNode(int val) {
            this.left = null;
            this.right = null;
            this.val = val;
        }
    }

    private TreeNode root=null;

    public boolean insert(int key){

    }
    public TreeNode search(int key){

    }
    public boolean remove(int key){

    }

    private void removeNode(TreeNode cur, TreeNode parent) {

    }
}

2.查找search

1.若根节点为空,返回null

2.若根节点不为空:

如果cur节点val==key,返回该节点

如果cur节点val<key,往右树查找

如果cur节点val>key,往左树查找

2.若找不到该节点,返回null

    public TreeNode search(int key){
        TreeNode cur=root;
        while(cur!=null){
            if (key < cur.val){
                cur=cur.left;
            }
            if (key>cur.val){
                cur=cur.right;
            }
            if(cur.val==key){
                return cur;
            }
        }
        return null;
    }

3.插入insert

1.如果树为空树,即root==null,直接插入:root=node;

2.如果树不为空树,则按照search操作的逻辑,一直向下查找到cur节点为null为止

同时用parent节点记录cur的父节点,最终用parent的val与key作比较,

判断node节点是插到parent的左边还是右边

    public boolean insert(int key){
        TreeNode node=new TreeNode(key);
        if(root==null){
            root=node;
            return true;
        }
        TreeNode cur=root;
        TreeNode parent=null;
        while(cur!=null){
            parent=cur;
            if(key<cur.val){
                cur=cur.left;
            } else {
                cur=cur.right;
            }
        }
        if (key< parent.val){
            parent.left =node;
        }else {
            parent.right =node;
        }
        return true;
    }

4.删除remove(难点)

设待删除结点为 cur, 待删除结点的双亲结点为 parent
1. cur.left == null
(1). cur root ,则 root = cur.right
(2). cur 不是 root cur parent.left ,则 parent.left = cur.right
(3). cur 不是 root cur parent.right ,则 parent.right = cur.right
2. cur.right == null
(1). cur root ,则 root = cur.left
(2). cur 不是 root cur parent.left ,则 parent.left = cur.left
(3). cur 不是 root cur parent.right ,则 parent.right = cur.left
3. cur.left != null && cur.right != null(难点)
需要使用 替换删除法 进行删除,即在它的右子树中寻找中序下的第一个结点 ( 关键码最小 ) ,用它的值填补到被删除节点中,再来处理该结点的删除问题

替换删除法:

代码实现如下:

    private void removeNode(TreeNode cur, TreeNode parent) {
        if (cur.left ==null){
            if (cur==root){
                cur=cur.right;
            }
            if (cur==parent.left){
                parent.left =cur.right;
            }
            if (cur==parent.right){
                parent.right =cur.right;
            }
        } else if (cur.right ==null){
            if (cur==root){
                cur=cur.left;
            }
            if (cur==parent.left){
                parent.left =cur.left;
            }
            if (cur==parent.right){
                parent.right =cur.left;
            }
        }else{//cur左右都不为空
            TreeNode target =cur.right;//右树的最小值
            TreeNode targetparent =cur;
            //1.找右树的最小值
            while(target.left !=null){
                targetparent = target;
                target = target.left;
            }
            //2.覆盖数值
            cur.val= target.val;
            //3.删除节点
            if (targetparent.left ==target) {
                targetparent.left = target.right;
            }else {
                targetparent.right = target.right;
            }
        }
    }

【注意】

在最后删除target节点的时候,要判断target节点是在targetparent的左边还是右边

5.性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有 n 个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:logN
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2

如果哪里有疑问的话欢迎来评论区指出和讨论,如果觉得文章有价值的话就请给我点个关注还有免费的收藏和赞吧,谢谢大家


http://www.kler.cn/a/400315.html

相关文章:

  • QList和QSet常用操作(查找、插入、排序、交集)
  • .NET 简介
  • Java多线程回顾总结
  • springboot如何获取控制层get和Post入参
  • Uniapp 引入 Android aar 包 和 Android 离线打包
  • MSTP知识点
  • 2.3 物理层设备
  • 无人机+无人车+机器狗:城市巷战突破技术详解
  • DataStream编程模型之数据源、数据转换、数据输出
  • 【蓝桥杯备赛】深秋的苹果
  • @quick-start/electron安装过程中的问题解决
  • CertiK安全调研报告:Web3.0桌面钱包的初步安全评估
  • vscode调试已经编译好的程序
  • ROS第九梯:ROS+VSCode+Python+C++自定义消息发布和订阅
  • ⚡️如何在 React 和 Next.js 项目里优雅的使用 Zustand
  • DAY30|贪心算法Part04|LeetCode:452. 用最少数量的箭引爆气球、435. 无重叠区间、763.划分字母区间
  • 【C++】用哈希表封装unordered_map和unordered_set
  • uni-app快速入门(十一)--常用JS API(上)
  • 全志科技嵌入式面试题及参考答案
  • 【论文阅读】Large Language Models for Equivalent Mutant Detection: How Far Are We?
  • vue3 + vite + ts 配置 @ 别名
  • python成长技能之正则表达式
  • python模块和包
  • 【漏洞复现】某全新H5购物商城系统存在前台任意文件上传漏洞(RCE)
  • 枚举Enum使用
  • # ubuntu安装openjdk 和 pycharm 并解决 pycharm 不能输入中文的问题