java实现二叉搜索树功能

【Java】二叉搜索树 实现树数据的数据库存储 二叉搜索树 1、 题目要求 ① 实现一个二叉搜索树, 提供添加、删除、查找、遍历功能,实现Insert(),delete(),visit(),search()方法 ② 利用接口实现通用Insert(),delete(),visit(),search() ③ 处理异常 ④ 实现树数据的数据库存储(自选数据库) 2、 环境准备 语言:java version ’1.8.0_221’ 平台:IntelliJ IDEA 2019.2.4 x64 数据库:MySQL 数据库可视化软件:Navicat 3、 题目解析 阅读详情

java实现 二叉搜索树功能

概念

二叉搜索树也成二叉排序树,它有这么一个特点,某个节点,若其有两个子节点,则一定满足,左子节点值一定小于该节点值,右子节点值一定大于该节点值,对于非基本类型的比较,可以实现Comparator接口,在本文中为了方便,采用了int类型数据进行操作。

要想实现一颗二叉树,肯定得从它的增加说起,只有把树构建出来了,才能使用其他操作。

二叉搜索树构建

谈起二叉树的增加,肯定先得构建一个表示节点的类,该节点的类,有这么几个属性,节点的值,节点的父节点、左节点、右节点这四个属性,代码如下


static class Node{
 Node parent;
 Node leftChild;
 Node rightChild;
 int val;
 public Node(Node parent, Node leftChild, Node rightChild,int val) {
   super();
   this.parent = parent;
   this.leftChild = leftChild;
   this.rightChild = rightChild;
   this.val = val;
 }
 public Node(int val){
   this(null,null,null,val);
 }
 public Node(Node node,int val){
   this(node,null,null,val);
 }
}

    这里采用的是内部类的写法,构建完节点值后,再对整棵树去构建,一棵树,先得有根节点,再能延伸到余下子节点,那在这棵树里,也有一些属性,比如基本的根节点root,树中元素大小size,这两个属性,如果采用了泛型,可能还得增加Comparator属性,或提供其一个默认实现。具体代码如下
 public class SearchBinaryTree {
private Node root;
private int size;
public SearchBinaryTree() {
 super();
}
}

增加

当要进行添加元素的时候,得考虑根节点的初始化,一般情况有两种、当该类的构造函数一初始化就对根节点root进行初始化,第二种、在进行第一次添加元素的时候,对根节点进行添加。理论上两个都可以行得通,但通常采用的是第二种懒加载形式。

在进行添加元素的时候,有这样几种情况需要考虑

   一、添加时判断root是否初始化,若没初始化,则初始化,将该值赋给根节点,size加一。

   二、因为二叉树搜索树满足根节点值大于左节点,小于右节点,需要将插入的值,先同根节点比较,若大,则往右子树中进行查找,若小,则往左子树中进行查找。直到某个子节点。

   这里的插入实现,可以采用两种,一、递归、二、迭代(即通过while循环模式)。

递归版本插入

public boolean add(int val){
   if(root == null){
     root = new Node(val);
     size++;
     return true;
   }
   Node node = getAdapterNode(root, val);
   Node newNode = new Node(val);
   if(node.val > val){
     node.leftChild = newNode;
     newNode.parent = node;
   }else if(node.val < val){
     node.rightChild = newNode;
     newNode.parent = node;
   }else{
     // 暂不做处理
   }
   size++;19     return true;
 }
 /**
  * 获取要插入的节点的父节点,该父节点满足以下几种状态之一
  * 1、父节点为子节点
  * 2、插入节点值比父节点小,但父节点没有左子节点
  * 3、插入节点值比父节点大,但父节点没有右子节点
  * 4、插入节点值和父节点相等。
  * 5、父节点为空
  * 如果满足以上5种情况之一,则递归停止。
  * @param node
  * @param val
  * @return
  */
 private Node getAdapterNode(Node node,int val){
   if(node == null){
     return node;
   }
   // 往左子树中插入,但没左子树,则返回
   if(node.val > val && node.leftChild == null){
     return node;
   }
   // 往右子树中插入,但没右子树,也返回
   if(node.val < val && node.rightChild == null){
     return node;
   }
   // 该节点是叶子节点,则返回
   if(node.leftChild == null && node.rightChild == null){
     return node;
   }
   if(node.val > val && node.leftChild != null){
     return getAdaptarNode(node.leftChild, val);
   }else if(node.val < val && node.rightChild != null){
     return getAdaptarNode(node.rightChild, val);
   }else{
     return node;
   }
 }

使用递归,先找到递归的结束点,再去把整个问题化为子问题,在上述代码里,逻辑大致是这样的,先判断根节点有没有初始化,没初始化则初始化,完成后返回,之后通过一个函数去获取适配的节点。之后进行插入值。

迭代版本

public boolean put(int val){
    return putVal(root,val);
  }
  private boolean putVal(Node node,int val){
    if(node == null){// 初始化根节点
      node = new Node(val);
      root = node;
      size++;
      return true;
    }
    Node temp = node;
    Node p;
    int t;
    /**
     * 通过do while循环迭代获取最佳节点,
     */
    do{ 
      p = temp;
      t = temp.val-val;
      if(t > 0){
        temp = temp.leftChild;
      }else if(t < 0){
        temp = temp.rightChild;
      }else{
        temp.val = val;
        return false;
      }
    }while(temp != null);
    Node newNode = new Node(p, val);
    if(t > 0){
      p.leftChild = newNode;
    }else if(t < 0){
      p.rightChild = newNode;
    }
    size++;
    return true;
  }

原理其实和递归一样,都是获取最佳节点,在该节点上进行操作。

论起性能,肯定迭代版本最佳,所以一般情况下,都是选择迭代版本进行操作数据。

删除

可以说在二叉搜索树的操作中,删除是最复杂的,要考虑的情况也相对多,在常规思路中,删除二叉搜索树的某一个节点,肯定会想到以下四种情况,

1、要删除的节点没有左右子节点,如上图的D、E、G节点

2、要删除的节点只有左子节点,如B节点

3、要删除的节点只有右子节点,如F节点

4、要删除的节点既有左子节点,又有右子节点,如 A、C节点

对于前面三种情况,可以说是比较简单,第四种复杂了。下面先来分析第一种

若是这种情况,比如 删除D节点,则可以将B节点的左子节点设置为null,若删除G节点,则可将F节点的右子节点设置为null。具体要设置哪一边,看删除的节点位于哪一边。

第二种,删除B节点,则只需将A节点的左节点设置成D节点,将D节点的父节点设置成A即可。具体设置哪一边,也是看删除的节点位于父节点的哪一边。

第三种,同第二种。

第四种,也就是之前说的有点复杂,比如要删除C节点,将F节点的父节点设置成A节点,F节点左节点设置成E节点,将A的右节点设置成F,E的父节点设置F节点(也就是将F节点替换C节点),还有一种,直接将E节点替换C节点。那采用哪一种呢,如果删除节点为根节点,又该怎么删除?

对于第四种情况,可以这样想,找到C或者A节点的后继节点,删除后继节点,且将后继节点的值设置为C或A节点的值。先来补充下后继节点的概念。

一个节点在整棵树中的后继节点必满足,大于该节点值得所有节点集合中值最小的那个节点,即为后继节点,当然,也有可能不存在后继节点。

但是对于第四种情况,后继节点一定存在,且一定在其右子树中,而且还满足,只有一个子节点或者没有子节点两者情况之一。具体原因可以这样想,因为后继节点要比C节点大,又因为C节点左右子节一定存在,所以一定存在右子树中的左子节点中。就比如C的后继节点是F,A的后继节点是E。

有了以上分析,那么实现也比较简单了,代码如下

public boolean delete(int val){
    Node node = getNode(val);
    if(node == null){
      return false;
    }
    Node parent = node.parent;
    Node leftChild = node.leftChild;
    Node rightChild = node.rightChild;
    //以下所有父节点为空的情况,则表明删除的节点是根节点
    if(leftChild == null && rightChild == null){//没有子节点
      if(parent != null){
        if(parent.leftChild == node){
          parent.leftChild = null;
        }else if(parent.rightChild == node){
          parent.rightChild = null;
        }
      }else{//不存在父节点,则表明删除节点为根节点
        root = null;
      }
      node = null;
      return true;
    }else if(leftChild == null && rightChild != null){// 只有右节点
      if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
        parent.leftChild = rightChild;
      }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
        parent.rightChild = rightChild;
      }else{
        root = rightChild;
      }
      node = null;
      return true;
    }else if(leftChild != null && rightChild == null){// 只有左节点
      if(parent != null && parent.val > val){// 存在父节点,且node位置为父节点的左边
        parent.leftChild = leftChild;
      }else if(parent != null && parent.val < val){// 存在父节点,且node位置为父节点的右边
        parent.rightChild = leftChild;
      }else{
        root = leftChild;
      }
      return true;
    }else if(leftChild != null && rightChild != null){// 两个子节点都存在
      Node successor = getSuccessor(node);// 这种情况,一定存在后继节点
      int temp = successor.val;
      boolean delete = delete(temp);
      if(delete){
        node.val = temp;
      }
      successor = null;
      return true;
    }
    return false;
  }

  /**
   * 找到node节点的后继节点
   * 1、先判断该节点有没有右子树,如果有,则从右节点的左子树中寻找后继节点,没有则进行下一步
   * 2、查找该节点的父节点,若该父节点的右节点等于该节点,则继续寻找父节点,
   *  直至父节点为Null或找到不等于该节点的右节点。
   * 理由,后继节点一定比该节点大,若存在右子树,则后继节点一定存在右子树中,这是第一步的理由
   *   若不存在右子树,则也可能存在该节点的某个祖父节点(即该节点的父节点,或更上层父节点)的右子树中,
   *   对其迭代查找,若有,则返回该节点,没有则返回null
   * @param node
   * @return
   */
  private Node getSuccessor(Node node){
    if(node.rightChild != null){
      Node rightChild = node.rightChild;
      while(rightChild.leftChild != null){
        rightChild = rightChild.leftChild;
      }
      return rightChild;
    }
    Node parent = node.parent;
    while(parent != null && (node == parent.rightChild)){
      node = parent;
      parent = parent.parent;
    }
    return parent;
  }

查找

查找也比较简单,其实在增加的时候,已经实现了。实际情况中,这部分可以抽出来单独方法。代码如下

public Node getNode(int val){
    Node temp = root;
    int t;
    do{
      t = temp.val-val;
      if(t > 0){
        temp = temp.leftChild;
      }else if(t < 0){
        temp = temp.rightChild;
      }else{
        return temp;
      }
    }while(temp != null);
    return null;
  }

二叉搜索树遍历

在了解二叉搜索树的性质后,很清楚的知道,它的中序遍历是从小到大依次排列的,这里提供中序遍历代码

public void print(){
    print(root);
  }
  private void print(Node root){
    if(root != null){
      print(root.leftChild);
      System.out.println(root.val);// 位置在中间,则中序,若在前面,则为先序,否则为后续
      print(root.rightChild);
    }
  }

 

【Java算法实战】java实现二叉搜索树功能 这里采用的是内部类的写法,构建完节点值后,再对整棵树去构建,一棵树,先得有根节点,再能延伸到余下子节点,那在这棵树里,也有一些属性,比如基本的根节点root,树中元素大小size,这两个属性,如果采用了泛型,可能还得增加Comparator属性,或提供其一个默认实现。第四种,也就是之前说的有点复杂,比如要删除C节点,将F节点的父节点设置成A节点,F节点左节点设置成E节点,将A的右节点设置成F,E的父节点设置F节点(也就是将F节点替换C节点),还有一种,直接将E节点替换C节点。if(parent! 阅读详情

相关推荐

Revit二次开发之双事件:空闲事件与DocumentChanged事件

对以下文章所展示的代码进行了修改,当前展示的代码可直接复制使用。 由于本人初学,下列语言为个人理解,如有错误请指正。   《引用1》中: 使用模态对话框,或者尽量保证事件在ExternalCommand的Execute函数或者ExternalApplication的OnStartup函数里面注册。 如果一定要使用非模态对话框,那么请使用ExternalEvent事件的Raise函数,强迫...

一个Revit二次开发的实习生 6147

java树结构查询及分页

树结构查询

weixin_45326523的博客 3577

OAK-D-Pro深度解析:从硬件融合到全天候SLAM实战

本文深度解析OAK-D-Pro硬件架构及其在SLAM领域的实战应用。作为SLAM的"六边形战士",OAK-D-Pro融合主动双目摄像头、结构光投射器、6轴IMU等传感器,实现全天候稳定工作。通过实测数据展示其在弱纹理环境、动态光照等复杂场景下的卓越表现,并提供SLAM实战技巧与开发指南,帮助开发者快速部署高效SLAM解决方案。

weixin_27244795的博客 183

java Tree 树状结构递归搜索算法;过滤保留父节点

初始树 /** * * 1 * / | \ * 2 3 4 * / \ /\ * 5 6 7 8 ...

qq_42420773的博客 6584

从零玩转GD32单片机CAN总线:手把手实战配置与源码解析

本文提供了一份基于GD32单片机的CAN总线实战入门指南。从硬件连接(GD32F103C8T6与TJA1050收发器)到软件配置,详细解析了CAN初始化、波特率计算、过滤器设置及中断收发等核心源码。通过手把手的回环测试示例与常见问题排查,帮助开发者快速掌握CAN总线通信的关键配置与调试技巧。

g5h6i7j的博客 481

SAP 货币类型和公司代码的货币设置

货币类型分为公司代码和集团货币,一般FI 10类型和集团货币 30,事务代码是8KEM; 设置货币类型的事务代码是OB22 在S/4 1809版本里编辑功能统合到事务代码FINSC_LEDGER 中了,这里集中了分类账和公司代码的设置; 设置多账簿的币种(会出现在BSEG和FAGLFLEXA表中) 汇率维护在TCURR表中,可通过BAPI_EXCHANGERATE_GETDETAIL函数获取。 CO货币的事务代码是成本控制范围货币:OKKP ,一般设置为货币码20和30; 另外, SCC4设置集团货币,

RichardYang2020的博客 1万+

Java 树型查找

java sql 树型查找

lijieaace的博客 791

到底什么是电源的斜波补偿,电源芯片CS引脚作用,一文讲清楚!

上文有提到电流环,其实电流环再细分也有很多模式,用的最多的是峰值电流模式峰值电流模式调节工作原理如下:(1)当输出负载增大时,输出电压降低,因此,Vc 增大,线性增加的电感电流只有升高到更大的值才能使 PWM 电流比较器翻转,开关管导通的时间增长,占空比增加,输入功率增加,因此输出电压增加,当输出电压增加到调节的范围内时,系统保持平衡。

jwgdhuwdhg的博客 1万+

java树形结构数据搜索

public static List<TreeNode> search(List<TreeNode> data, String text) { List<TreeNode> res = new ArrayList<>(); for (TreeNode treeNode : data) { List<TreeNode> children = treeNode.getChildren()...

程序猿的博客 1954

MATLAB 2022b 用户专属:保姆级IPOPT求解器安装配置全流程(含OPTI工具箱)

本文为MATLAB 2022b用户提供IPOPT求解器的详细安装与配置指南,涵盖OPTI工具箱的适配安装、环境变量设置及常见问题解决方案。通过实战案例演示非线性优化问题的求解过程,帮助用户高效部署这一强大的优化工具,提升工程计算效率。

weixin_29092031的博客 405

MDF和DHF、DMR、DHR三者差异?注册与备案文件?医疗器械产品技术要求编写指导原则

定义:设计历史文档(DHF ) 指的是描述某医疗器械成品设计过程的有关记录。内容:DHF包括设计开发活动的所有记录。从最初的策划、客户需求、设计输入,设计输出、设计验证、设计确认、所有的设计评审,设计转换,以及设计变更相关的所有记录。均属于DHF的一部分。要求:各制造商应为每个类型的器械建立并保持设计历史文件。设计历史文件应包含或引用必要的记录,以证实设计符合经批准的设计计划和法规的要求。

学海无涯的专栏 9110

代码笔记2:java实现多层主题树结构查询

实现网站中常见的多层主题树结构查询。其数据结构是一个多层的树形结构,父主题包含一个子主题的列表,每一个子主题又包含下一级子主题的列表。通过一个接口查询所有的主题。

qq_37398465的博客 2328

在 SAP S/4HANA Public Cloud 中做产品扩展:从 Key User 到 ABAP Cloud 与 BTP 的三轨实践指南

摘要:SAP S/4HANA Public Cloud 提供三种扩展方式(key user、developer extensibility 和 side-by-side),遵循 clean core 原则确保升级稳定。key user 扩展适合无代码轻量改良,developer extensibility 用于受控 ABAP 开发,side-by-side 则适用于云原生独立应用。文章通过销售订单优先级字段、退货审批微服务和采购校验等案例,说明不同扩展路径的适用场景与实现方法,帮助开发者在三系统景观中合理选

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 294

二叉搜索树实现删除功能 Java

该代码定义了一个delete方法,其作用是从二叉搜索树里删除具有指定值的节点。若树为空或者指定值的节点不存在,会输出相应提示信息。删除节点时,会依据节点的子节点情况分三种情形处理:叶子节点、有两个子节点、仅有一个子节点。此delete方法能依据节点的不同情况正确删除二叉搜索树中的指定节点。不过,代码里调用的Search和min方法并未给出实现,在使用时需要确保这些方法已正确实现。

2202_75747703的博客 641

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java实现二叉搜索树(增删功能)

说些废话 二叉搜索树,左节点的值<当前节点的值<右节点的值 二叉搜索树难在删除,我用Java递归实现删除代码,并且附上注释解释,做个笔记 代码 BinaryTreeClass .java import java.util.Stack; public class BinaryTreeClass { // 中序遍历,用来验证是否删除成功 public void midorder(TreeNode curnode){ Stack<TreeNode> stack = new Sta

qq_34060370的博客 257

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

关于二叉搜索树功能的Java实现

二叉搜索树添加,删除,遍历Java代码实现。

iFleetingtime的博客 1509

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【JAVA】二叉搜索树的一些功能实现(递归)

用java实现搜索二叉树的查找,删除,添加功能

m0_57248752的博客 416

java 集合集成树_Java底层基于二叉搜索树实现集合和映射/集合Set功能详解

本文实例讲述了Java底层基于二叉搜索树实现集合和映射功能。分享给大家供大家参考,具体如下:前言:在第5章的系列学习中,已经实现了关于二叉搜索树的相关操作,详情查看第5章即可。在本节中着重学习使用底层是我们已经封装好的二叉搜索树相关操作来实现一个基本的集合(set)这种数据结构。集合set的特性:集合Set存储的元素是无序的、不可重复的。为了能达到这种特性就需要寻找可以作为支撑的底层数据结构。这里...

weixin_29735819的博客 174

java实现二叉搜索树的基本功能

在二叉查找树中: (01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值; (02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值; (03) 任意节点的左、右子树也分别为二叉查找树。 (04) 没有键值相等的节点(no duplicate nodes)。 直接上个码: /** * @注:泛型T必须是实现了Comparable接口。 * * @aut...

Linging_24的博客 308

java :非递归方法的二叉搜索树,实现部分功能

public class BinarySearchTree { /** * * @author Administrator *嵌套类构造结点 * @param */ private static class BinaryNode{ public Integer data; public BinaryNode lchild; public BinaryNo

Cool_ben的博客 961

Java实现二叉搜索树的基本功能

/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package javaapplication24; import java.util.Scanner; /** * * @author.

weixin_57769964的博客 320

【数据结构】二叉搜索树(Java + 链表实现)

Map接口是独立的实现Iterable接口的集合都是可以使用 for - Each 语句进行打印的搜索性能会非常高。

明志の博客 1956

二叉搜索树(Binary Search Tree)Java实现详解

任意节点的左子树所有节点值小于当前节点值任意节点的右子树所有节点值大于当前节点值每个节点的左右子树也都是BST。

amingya9的博客 1453

二叉搜索树的构造(Java实现)

二叉搜索树的学习笔记,使用Java语言对二叉搜索树进行了构造、添加元素、是否为空的判断、当前节点的个数判断以及是否包含某个元素的递归实现

世纪末的架构师的博客 3714

java实现二叉搜索树及二叉树测试

java实现二叉搜索树及二叉树测试 二叉树相关知识: 二叉树是每个节点都不能有多于两个儿子的树 二叉树的一个性质是一颗平均二叉树的深度要比节点数N小得多 二叉树的平均深度为O(N\sqrt NN​) 二叉查找树的平均深度为O(log⁡N\log NlogN) 关于删除节点: a. 若删除的节点是叶节点则直接删除 b. 若删除的是有两个儿子的节点则先用被删除节点的右子树的最小值覆盖被删除节点的值,...

LOHAS的博客 1539

Java 代码实现 二叉树(Binary Tree)

Java 代码基本实现 二叉树数据存储规则节点类 Node.java操作功能类 Binary.javaApp.java 数据存储规则 左子树上的所有节点值均小于根节点值 右子树上的所有节点值均不小于根节点值 左右子树也满足上述两个条件 节点类 Node.java public class Node { private String data; private Node lef...

Shawn Jeon`s blog 684
上一篇: Springboot+Easyexcel将数据写入模板文件并导出Excel
下一篇: Java 中常用的进制转换
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值