入门数据结构JAVADS——如何构建一棵简单二叉排序树

目录

前言

什么是二叉排序树

二叉排序树的特点

二叉排序树示意图

构建二叉排序树

 插入元素

 搜索元素

 删除元素

完整代码

结尾

前言

在整个十一月,笔者因为一些原因停笔了,但马上迈入12月进而进入2025年,笔者决定不再偷懒了,继续更新以促进学习的积极性.闲话说到这,今天更新的是如何构建一个简单的二叉排序树

什么是二叉排序树

二叉排序树(Binary Search Tree,简称 BST)是一种特殊的二叉树,它的每个节点都满足以下性质:

  1. 左子树上所有节点的值,都小于根节点的值。
  2. 右子树上所有节点的值,都大于根节点的值。
  3. 左子树和右子树本身也都是二叉排序树(递归定义)。

二叉排序树的特点

  • 值的唯一性:二叉排序树中每个节点的值必须是唯一的(不允许重复值)。
  • 有序性:中序遍历(左-根-右)二叉排序树时,会得到一个递增的有序序列
  • 动态性:支持动态插入和删除元素,能够随时维护有序性。
  • 时间复杂度:平均情况下插入、查找、删除的时间复杂度为 O(log⁡n),但在极端情况下(树退化为链表),复杂度可能退化到 O(n)。

举个例子

二叉排序树示意图

假设我们依次插入以下数字:50, 30, 70, 20, 40, 60, 80
构造的二叉排序树如下:

        50
      /    \
    30      70
   /  \    /  \
 20   40  60   80

此时,中序遍历二叉树,即可得到顺序排列. 

构建二叉排序树

想要写一棵简单的二叉排序树,大致需要三个方法,分别是 插入结点,查找结点,删除结点

我们首先创建好结点类

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

public  TreeNode root;

 插入元素

插入元素是比较简单的,思路如下:

1.   首先判断树是不是空的,如果是空的,插入元素即为根

2.   如果不是空的,那么就借助双亲结点,去找需要插入结点的位置,然后再和双亲结点比较,看看左子树还是右子树

  public boolean insert(int val)
  {
      if(root==null)
      {
          root=new TreeNode(val);
          return true;
      }
      TreeNode parent=null;
      TreeNode cur=root;
      while(cur!=null)
      {
         if(cur.val>val)
         {
             parent=cur;
             cur=cur.left;
         } else if (cur.val<val) {
             parent=cur;
             cur=cur.right;
         }
         else
         // 如果是等于就不能插入了,二叉排序树没办法容纳一样的key
         {
             return false;
         }
      }
      if(parent.val>val)
      {
          parent.left=new TreeNode(val);
      }
      else
      {
          parent.right=new TreeNode(val);
      }
      return true;
  }

***************** 需要注意的是,二叉排序树不能插入重复的元素.*********************

 搜索元素

搜索元素也很简单,因为二叉排序树本身就是为了提高搜索效率而产生的,

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

 删除元素

  删除元素是比较难的,如果笔者自己想想就会发现,好像有好多种情况要去想,这里笔者也不绕弯子,前辈们已经替我们总结出来了,大致会有三种情况

但在分情况之前 首先:设待删除结点为 cur, 待删除结点的双亲结点为 parent, 其次,要确定,待删除结点是否存在.

public  boolean remove(int val)
  {
      TreeNode parent=null;
      TreeNode cur=root;
      while(cur!=null)
      {
          if(cur.val>val)
          {
              parent=cur;
              cur=cur.left;
          }
          else if(cur.val<val)
          {
              parent=cur;
              cur =cur.right;
          }
          else
          {
              // 找到了
              removeNode(cur,parent);
              return true;
          }
      }
      return false;
  }

 接下来我们完善 removeNode 

第一种情况,待删结点没有左子树

这种情况,我们就让它的右子树结点和双亲结点连接上就好了.

但也有个前提,他不是根节点,所以要考虑到这一点

代码如下:

   if(cur.left==null)
        // 左边为空
        {
            if(cur==root)
            {
                root=root.right;
                return;
            }
            else if(cur==parent.left)
            {
                parent.left=cur.right;
                return ;
            }
            else
            {
                parent.right=cur.right;
                return ;
            }

        }

 如果是双亲结点的左子树,就是  parent.left=cur.right;

 如果是双亲结点的右子树,就是  parent.right=cur.right;

第二种情况,待删结点没有右子树

同理,代码如下

      else if (cur.right==null)
        // 右边为空
        {
         if(cur==root)
         {
             root=root.left;
         }
         else if(cur==parent.left)
         {
             parent.left=cur.left;
         }
         else
         {
             parent.right=cur.left;
         }
        }

 第三种,左右都不为空

我们的思路:
1.找到 cur

2.找cur左子树最右边的或者cur右子树最左边的,来替换我们的这个cur结点

3.替换完成以后,再把结点删除,请注意,有两种可能.如图所示

 else{
            TreeNode ansparent = cur;
            TreeNode ans = cur.right;
            // 去找右子树最左边的
            while(ans.left!=null)
            {
                ansparent=ans;
                ans=ans.left;
            }
            // 找到以后,也要分情况
            cur.val=ans.val;
            if(ansparent.left == ans)
            {
                ansparent.left = ans.right;
            }
            else
            {
                ansparent.right=ans.right;
            }
        }

完整代码

package searchtree;

public class SearchTree
    // 二叉搜索树
{
    static  class TreeNode
    {
        public  int val;
        public  TreeNode left;
        public  TreeNode right;
        public TreeNode(int val)   {
            this.val = val;
        }
    }
    public  TreeNode root;
    public  boolean search(int key)
    {
      TreeNode cur=root;
        while(cur!=null)
        {
            if(cur.val>key)
            {
                cur=cur.left;
            }
            else if(cur.val<key)
            {
                cur =cur.right;
            }
            else
            {
                return true;
            }
        }
        return false;
    }
  public boolean insert(int val)
  {
      if(root==null)
      {
          root=new TreeNode(val);
          return true;
      }
      TreeNode parent=null;
      TreeNode cur=root;
      while(cur!=null)
      {
         if(cur.val>val)
         {
             parent=cur;
             cur=cur.left;
         } else if (cur.val<val) {
             parent=cur;
             cur=cur.right;
         }
         else
         // 如果是等于就不能插入了,二叉排序树没办法容纳一样的key
         {
             return false;
         }
      }
      if(parent.val>val)
      {
          parent.left=new TreeNode(val);
      }
      else
      {
          parent.right=new TreeNode(val);
      }
      return true;
  }
  public  boolean remove(int val)
  {
      TreeNode parent=null;
      TreeNode cur=root;
      while(cur!=null)
      {
          if(cur.val>val)
          {
              parent=cur;
              cur=cur.left;
          }
          else if(cur.val<val)
          {
              parent=cur;
              cur =cur.right;
          }
          else
          {
              // 找到了
              removeNode(cur,parent);
              return true;
          }
      }
      return false;
  }
    private void removeNode(TreeNode cur, TreeNode parent)
    {
        if(cur.left==null)
        // 左边为空
        {
            if(cur==root)
            {
                root=root.right;
                return;
            }
            else if(cur==parent.left)
            {
                parent.left=cur.right;
                return ;
            }
            else
            {
                parent.right=cur.right;
                return ;
            }

        }
        else if (cur.right==null)
        // 右边为空
        {
         if(cur==root)
         {
             root=root.left;
         }
         else if(cur==parent.left)
         {
             parent.left=cur.left;
         }
         else
         {
             parent.right=cur.left;
         }
        }
        // 左右都不为空
        // 思路
        // 1.找到 cur
        // 2.找cur左子树最右边的或者cur右子树最左边的,来替换我们的这个cur结点
        else{
            TreeNode ansparent = cur;
            TreeNode ans = cur.right;
            // 去找右子树最左边的
            while(ans.left!=null)
            {
                ansparent=ans;
                ans=ans.left;
            }
            // 找到以后,也要分情况
            cur.val=ans.val;
            if(ansparent.left == ans)
            {
                ansparent.left = ans.right;
            }
            else
            {
                ansparent.right=ans.right;
            }
        }
    }
}

结尾

这一篇算是我的笔记,所以写的会比较潦草,提前sorry了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/926999.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】四大图像分类网络之AlexNet

AlexNet是由Alex Krizhevsky、Ilya Sutskever&#xff08;均为Hinton的学生&#xff09;和Geoffrey Hinton&#xff08;被誉为”人工智能教父“&#xff0c;首先将反向传播用于多层神经网络&#xff09;在2012年ImageNet图像分类竞赛中提出的一种经典的卷积神经网络。AlexNet在…

基于 Python、OpenCV 和 PyQt5 的人脸识别上课打卡系统

大家好&#xff0c;我是Java徐师兄&#xff0c;今天为大家带来的是基于 Python、OpenCV 和 PyQt5 的人脸识别上课签到系统。该系统采用 Python 语言开发&#xff0c;开发过程中采用了OpenCV框架&#xff0c;Sqlite db 作为数据库&#xff0c;系统功能完善 &#xff0c;实用性强…

DevOps工程技术价值流:Jenkins驱动的持续集成与交付实践

一、Jenkins系统概述 Jenkins&#xff1a;开源CI/CD引擎的佼佼者 Jenkins&#xff0c;作为一款基于Java的开源持续集成&#xff08;CI&#xff09;与持续交付&#xff08;CD&#xff09;系统&#xff0c;凭借其强大的插件生态系统&#xff0c;成为DevOps实践中不可或缺的核心…

亚马逊开发视频人工智能模型,The Information 报道

根据《The Information》周三的报道&#xff0c;电子商务巨头亚马逊&#xff08;AMZN&#xff09;已开发出一种新的生成式人工智能&#xff08;AI&#xff09;&#xff0c;不仅能处理文本&#xff0c;还能处理图片和视频&#xff0c;从而减少对人工智能初创公司Anthropic的依赖…

mac下安装Ollama + Open WebUI + Llama3.1

本文介绍mac下安装Ollama Open WebUI Llama3.1 8b具体步骤。 目录 推荐配置Ollama Open WebUI Llama3.1简介安装Ollama安装Open WebUI 推荐配置 m1以上芯片&#xff0c;16g内存&#xff0c;20g以上硬盘空间 Ollama Open WebUI Llama3.1简介 Ollama: 下载&#xff0c;管理…

Swift实现高效链表排序:一步步解读

文章目录 前言摘要问题描述题解解题思路Swift 实现代码代码分析示例测试与结果 时间复杂度空间复杂度总结关于我们 前言 本题由于没有合适答案为以往遗留问题&#xff0c;最近有时间将以往遗留问题一一完善。 148. 排序链表 不积跬步&#xff0c;无以至千里&#xff1b;不积小流…

小程序-基于java+SpringBoot+Vue的校园快递平台系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

网页开发的http基础知识

请求方式-GET&#xff1a;请求参数在请求行中&#xff0c;没有请求体&#xff0c;如&#xff1a;/brand/findAll?nameoPPo&status1。GET请求大小在浏览器中是有限制的请求方式-POST&#xff1a;请求参数在请求体中&#xff0c;POST请求大小是没有限制的 HTTP请求&#xf…

Qt自定义 Qt Designer 插件

创建 Qt Designer 插件项目 Qt 提供两种设计插件的 API&#xff0c;可以用于扩展 Qt 的功能。高级 API 用于设计插件以扩展 Qt 的功能&#xff0c;例如定制数据库驱动、图像格式、文本编码、定制样式等。Qt Designer 里大量采用了插件&#xff0c;点击 Qt Creator 的“Help”-…

周鸿祎再次“创业”,盯上百度

周鸿祎特地拍了部短剧来推广的新产品&#xff0c;终于上线了。 11月27日晚间&#xff0c;360正式发布多模态内容创作引擎“纳米搜索”。 作为当前AI应用最红的赛道之一&#xff0c;AI搜索已经有腾讯、秘塔、商汤、抖音等公司入局。传统搜索老大百度也在发力。竞争不妨碍有搜索…

003 MATLAB基础计算

01 方程组的求解 多项式及其运算 多项式在MATLAB中以向量形式存储。 即n次多项式用一个长度为n1的系数向量来表示&#xff0c;且按降幂&#xff0c;缺少的幂次对应的向量元素为0。 多项式的运算主要包括多项式的四则运算、求导、求值和求根运算 多项式的四则运算&#xff1a…

金蝶云苍穹:个人上传授权文件

金蝶云苍穹开发者门户--下载文件地址。

解决windows下php8.x及以上版本,在Apache2.4中无法加载CURL扩展的问题

本文已首发于&#xff1a;秋码记录 若你也想搭建一个个人博客&#xff0c;可参考&#xff1a;国内 gitee.com Pages 下线了&#xff0c;致使众多站长纷纷改用 github、gitlab Pages 托管平台 在日新月异的信息化下&#xff0c;软件也在跟随着互联网的脚步&#xff0c;逐步推进…

数据库管理-第267期 23ai:Oracle Data Redaction演示(20241128)

数据库管理267期 2024-11-286 数据库管理-第267期 23ai&#xff1a;Oracle Data Redaction演示&#xff08;20241128&#xff09;1 示例表及数据2 创建编校策略2.1 名字全编校2.2 电话部分编校 3 DML演示3.1 场景13.2 场景2 总结 数据库管理-第267期 23ai&#xff1a;Oracle Da…

根据电池容量及功耗估算充电及放电时间

根据电池容量和功耗估算充电和放电时间的方法可以通过以下简单的公式进行&#xff1a; 1. 估算放电时间 放电时间是指电池在一定功耗下&#xff0c;能够持续供应电力的时间。可以使用以下公式&#xff1a; 解释&#xff1a; 电池容量&#xff1a;电池的容量一般以毫安时&…

【Maven】继承和聚合

5. Maven的继承和聚合 5.1 什么是继承 Maven 的依赖传递机制可以一定程度上简化 POM 的配置&#xff0c;但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同 jar 包的相同版本&#xff0c;且这些模块之间不存在依赖关系&#xff0c;这就导致同一个依赖…

对抗攻击算法:FGSM和PGD

FGSM 传送门 FGSM 利用了梯度上升的思想&#xff0c;通过损失函数相对于输入图像的梯度来找到 最容易 迷惑网络的方向&#xff0c;并沿着这个方向对图像进行微小的扰动。 FGSM 的基本想法是&#xff0c;沿着这个梯度的符号方向对图像进行微调&#xff0c;以最大化损失函数。具…

Matlab mex- setup报错—错误使用 mex,未检测到支持的编译器...

错误日志&#xff1a; 在使用mex编译时报错提示&#xff1a;错误使用 mex&#xff0c;未检测到支持的编译器。您可以安装免费提供的 MinGW-w64 C/C 编译器&#xff1b;请参阅安装 MinGW-w64 编译器。有关更多选项&#xff0c;请访问https://www.mathworks.com/support/compile…

内网穿透步骤

步骤 第一次需要验证token window和linux的方法不同。 然后 启动 cpolar 服务&#xff1a; 在命令窗口中输入 cpolar.exe htttp 8080&#xff0c;启动内网穿透服务。确保命令窗口保持开启状态&#xff0c;以维持穿透效果。 cpolar.exe hhttp 8080 成功后 注意事项 命令窗口…

系统架构:MVVM

引言 MVVM 全称 Model-View-ViewModel&#xff0c;是在 MVP&#xff08;Model-View-Presenter&#xff09;架构模式基础上的进一步演进与优化。MVVM 与 MVP 的基本架构相似&#xff0c;但 MVVM 独特地引入了数据双向绑定机制。这一创新机制有效解决了 MVP 模式中 Model 与 Vie…