数据结构—树(java实现)

目录

  • 一、树的基本概念
    • 1.树的术语
    • 2.常见的树结构
  • 二、节点的定义
  • 三、有关树结构的操作
    • 1.按照数组构造平衡 二叉搜索树
    • 2.层序遍历树
    • 3.前、中、后序遍历树
      • (1).前序遍历树
      • (2).中序遍历树
      • (3).后序遍历树
      • (4).各种遍历的情况的效果对比
  • 4.元素添加
  • 5.元素删除
    • 1.删除叶子节点
    • 2.删除单一子节点的节点
    • 3.删除双子节点的节点
    • 4.总结代码

一、树的基本概念

1.树的术语

树是由节点和边构成的一种层次性的结构,包括一个根节点,根节点下面连接很多个子节点。树结构的术语如下:
1、根节点:树的第一个节点,没有父节点。
2、子节点:根节点下面的节点为子节点。
3、叶子节点:没有子节点的节点。
4、父节点:子节点的上面的节点为父节点。
5、子树:一个节点以及其所有的子节点、以及子节点的子节点构成子树。
6、森林:森林是指互相不交并树的集合。
7、节点的权:节点的值
8、路径:从根节点到该节点的距离。

2.常见的树结构

1.二叉树:每一个节点最多只有两个子节点的树叫做二叉树。
2.完全二叉树:按照节点的输入顺序进行构造树,使每一层的树节点达到要求的规定值(2^n-1)。
3.有序二叉树:每一个节点最多只有两个子节点的树,且左子节点小于父节点的值,右子节点大于父节点的值。
4.二叉平衡树:每个节点的左子树和右子树的高度差绝对值不超过1。
5.红黑树:是一种自平衡的二叉查找树。

二、节点的定义

节点是树构造的基本单元,树是由节点按照一定顺序构造而出的。

package Tree;public class Node {Node left;Node right;int value;public Node(int value) {this.value = value;}public Node() {}@Overridepublic String toString() {return "Node{" +"left=" + left +", right=" + right +", value=" + value +'}';}
}

节点的定义需要包括空参构造有参构造,以及节点的值,节点的左子节点和右子节点。

三、有关树结构的操作

1.按照数组构造平衡 二叉搜索树

根据输入的数组,直接构造平衡 二叉搜索树,不需要进行调整,左旋右旋等操作,非常简便有效的操作

    public void makeTree(int[] nums){Arrays.sort(nums);Node node = fenzhi(nums,0,nums.length-1);root = node;}public Node fenzhi(int[] nums,int left,int right){if(left > right){return null;}int mid = (left+right)/2;Node head = new Node(nums[mid]); // 创建当前节点head.left = fenzhi(nums,left,mid-1);head.right = fenzhi(nums,mid+1,right);return head;}

运行代码如下:

package Tree;public class Test {public static void main(String[] args) {int[] nums = {1,4,9,5,2,10,18,3};Tree tree = new Tree();tree.makeTree(nums);tree.cengxu();}
}

运行结果如下:
在这里插入图片描述

2.层序遍历树

层序遍历需要用到队列辅助进行,队列具有先进先出的效果,比较适合进行层序遍历的操作。

 public void cengxu(){Node head = root;Queue<Node> queue = new LinkedList<>();queue.offer(head);while (!queue.isEmpty()){Node node = queue.poll();if(node.left != null){queue.offer(node.left);}if(node.right != null){queue.offer(node.right);}System.out.println(node.value);}}

3.前、中、后序遍历树

(1).前序遍历树

    public void beforeOrder(Node node){if(node == null){return;}System.out.print(node.value+" ");beforeOrder(node.left);beforeOrder(node.right);}

(2).中序遍历树

    public void inOrder(Node node){if(node == null){return;}inOrder(node.left);System.out.print(node.value+" ");inOrder(node.right);}

(3).后序遍历树

    public void LastOrder(Node node){if(node == null){return;}LastOrder(node.left);LastOrder(node.right);System.out.print(node.value+" ");}

(4).各种遍历的情况的效果对比

package Tree;public class Test {public static void main(String[] args) {int[] nums = {1,4,9,5,2,10,18,3};Tree tree = new Tree();tree.makeTree(nums);System.out.println("————————————————————————层序遍历————————————————");tree.cengxu();System.out.println(" ");System.out.println("————————————————————————前序遍历————————————————");tree.beforeOrder(tree.root);System.out.println(" ");System.out.println("————————————————————————中序遍历————————————————");tree.inOrder(tree.root);System.out.println(" ");System.out.println("————————————————————————后序遍历————————————————");tree.LastOrder(tree.root);}
}

运行结果如下:
在这里插入图片描述

4.元素添加

添加元素需要按照有序二叉树的形式添加元素,需要判断该值与节点值的大小,直到找到与其符合的位置,并且完成插入操作,代码如下:

public void insert(int num){Node node = new Node(num);Node head = root;if(root == null){root  = node;}while(true){if(num <head.value){if(head.left == null){head.left = node;break;}else{head = head.left;}} else if (num >= head.value) {if(head.right == null){head.right = node;break;}else{head = head.right;}}}}

5.元素删除

树节点的删除需要分成三种情况1.删除叶子节点2.删除只有一个子节点的节点3.删除两侧节点齐全的节点

1.删除叶子节点

1.找到要删除的元素
2.找到要删除元素的父节点
3.判断其父节点是否为空
4.父节点为空的话为:则该节点为根节点 可以将 root = null
5.父节点不为空的话:判断是父节点的左子节点还是父节点的右子节点 后删除

2.删除单一子节点的节点

1.找到要删除的节点
2,找到要删除节点的父节点
3.考虑有没有父节点
4.没有父节点:判断该节点有左子树还是右子树,如果目标节点有左子树的话 root = root.left 如果目标节点有右子树的话 root = root.right
5.有父节点的情况下:1、判断该节点是父节点的左子节点还是右子节点 左子节点的情况下:判断该节点有左子树还是右子树,如果目标节点有左子树的话 parent.left =target.left 如果目标节点有右子树的话 parent.left = target.right。2、判断该节点是父节点的左子节点还是右子节点 右子节点的情况下:判断该节点有左子树还是右子树,如果目标节点有左子树的话 parent.right = target.left 如果目标节点有右子树的话 parent.right = target.right。

3.删除双子节点的节点

1.找目标节点右子树的最小值(或者左子树的最大值)替换掉要删除的值
2.找目标节点右子树的最小值(或者左子树的最大值

4.总结代码

   //查找目标元素public Node search(int num){Node index = root;while(index!=null && index.value!=num){if(num > index.value){index = index.right;}else{index = index.left;}}return index;}//查找目标元素的父节点public Node searchParent(int num){Node node = root;while (node != null) {if (num < node.value) {if (node.left != null && node.left.value == num) {return node;}node = node.left;}else if (num >= node.value) {if (node.right != null && node.right.value == num) {return node;}node = node.right;}}return null;}//查找目标元素的右子树的最小值public int min(Node node){Node index = node;while(index.left != null){index = index.left;}return index.value;}//删除代码public void delete(int num){if(root == null){System.out.println("空树");return;}Node target = search(num);if(target == null){System.out.println("没有这个节点");return;}Node parent = searchParent(num);if(target.left == null && target.right == null){
//            删除叶子节点
//            父节点为空if(parent == null){root = null;return;}
//            父节点存在,且左子树if(parent.left != null && parent.left.value==num){parent.left = null;}else{
//                父节点存在,为右孩子parent.right = null;}}else if(target.left != null && target.right != null){
//            删除两个子树的int min = min(target.right);delete(min);target.value = min;}else{
//            删除一个子树的
//            没有父节点if(parent == null){
//                判断目标节点有左子树if(target.left != null){root = root.left;}else{root = root.right;}return;}
//            有父节点
//            目标节点是父节点的左子节点if(parent.left != null && parent.left.value==num){
//                判断目标节点是有左/右节点if(target.left!=null){parent.left = target.left;}else{parent.left = target.right;}
//                目标节点是父节点的右子节点}else{if(target.left!=null){parent.right = target.left;}else{parent.right=target.right;}}}}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SPI 机制与 Spring Boot AutoConfiguration 对比解析

一、架构效率革命性提升 1.1 类加载效率跃升 Spring Boot 2.7引入的AutoConfiguration.imports采用清单式配置加载&#xff0c;对比传统SPI机制&#xff1a; 传统SPI扫描路径&#xff1a;META-INF/services/** Spring Boot新方案&#xff1a;META-INF/spring/org.springfram…

node-red dashboard

安装&#xff1a; npm install node-red-dashboard 访问&#xff1a; http://127.0.0.1:1880/ui 1. 创建一个新的 Dashboard 页面: 在 Node-RED 编辑器中&#xff0c;拖动一个 ui_dashboard 节点到工作区&#xff0c;并将其连接到你的数据流。 2. 配置 Dashboard 节点: 双击…

深入理解现代C++在IT行业中的核心地位与应用实践

深入理解现代C在IT行业中的核心地位与应用实践 一、C在IT行业中的不可替代性 现代IT行业中&#xff0c;C凭借其零成本抽象和系统级控制能力&#xff0c;在以下关键领域保持不可替代地位&#xff1a; 应用领域C优势体现典型应用案例高性能计算直接内存管理&#xff0c;SIMD指令…

医院挂号预约小程序|基于微信小程序的医院挂号预约系统设计与实现(源码+数据库+文档)

医院挂号预约小程序 目录 基于微信小程序的医院挂号预约系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、小程序用户端 2、系统服务端 &#xff08;1&#xff09; 用户管理 &#xff08;2&#xff09;医院管理 &#xff08;3&#xff09;医生管理 &#xf…

2025最新版Ubuntu Server版本Ubuntu 24.04.2 LTS下载与安装-详细教程,细致到每一步都有说明

官网 https://ubuntu.com/ 下载 点击菜单 Prodercts> Ubuntu OS>Ubuntu Server 点击下载 下载后会有个弹窗 安装 选择第一个 install Ubuntu Server 直接默认&#xff0c;选择English 【默认】 选择键盘布局【默认】 选择安装配置【默认】 配置网络 我这里选择…

【AI】NLP

不定期更新&#xff0c;建议关注收藏点赞。 目录 transformer大语言模型Google Gemma疫情网民情绪识别 整体框架 baseline构建 模型调参、模型优化、其他模型 数据trick、指标优化、magic feature 数据增强、伪标签、迁移学习 模型融合sklearn中TFIDF参数详解 频率阈值可以去掉…

vscode正则表达式使用

小标题 ^\d.\d.\d\s.*$ ^表示匹配字符串的开头。\d\.\d\.\d表示匹配一到多个数字&#xff0c;接着一个小数点&#xff0c;再接着一到多个数字&#xff0c;然后又一个小数点和一到多个数字&#xff0c;用来匹配类似 “2.1.1” 这样的标题号部分。\s表示匹配一个空格。.*表示匹配…

TCP/IP三次握手的过程,为什么要3次?

一&#xff1a;过程 第一次&#xff08;SYN&#xff09;&#xff1a; 客户端发送一个带有SYN标志的TCP报文段给服务器&#xff0c;设置SYN1&#xff0c;并携带初始序列号Seqx&#xff08;随机值&#xff09;&#xff0c;进入SYN_SENT状态。等待服务器相应。 第二次&#xff08…

vue-将组件内容导出为Word文档-docx

1. 安装依赖 首先&#xff0c;我们需要安装docx库&#xff0c;以便在前端生成Word文档。可以通过以下命令进行安装&#xff1a; npm install docx 2. 实现导出功能 2.1 初始化文档 使用docx库创建一个新的文档实例&#xff0c;并定义文档的结构和内容。我们使用Document、…

uni-app常用模板

列表样式一 ,下拉翻页查询,效果图及代码 <template><z-paging ref="paging" v-model="dataList" @query="queryList"><!-- 需要固定在顶部不滚动的view放在slot="top"的view中,如果需要跟着滚动,则不要设置slot=&q…

鸿蒙移动应用开发--UI组件布局

实验要求&#xff1a; 制作一个B站视频卡片界面&#xff0c;大致如下图所示&#xff0c;要求应用到线性布局、层叠布局等相关课堂知识。背景图、logo及文本内容不限。 实验环境 &#xff1a;DevEco Studio 实验过程&#xff1a; 步骤1&#xff1a;创建项目 1. 在您的开发环境…

NVIDIA TensorRT 深度学习推理加速引擎详解

NVIDIA TensorRT 深度学习推理加速引擎详解 文章目录 NVIDIA TensorRT 深度学习推理加速引擎详解引言文章结构 第一部分&#xff1a;TensorRT概述什么是TensorRT&#xff1f;TensorRT的核心功能和优势1. 图优化2. 量化支持3. 动态形状支持4. 多平台支持5. 编程接口6. 性能优势 …

如何用Spring AI构建MCP Client-Server架构

现代 Web 应用正加速与大语言模型(LLMs)深度融合,构建超越传统问答场景的智能解决方案。为突破模型知识边界,增强上下文理解能力,开发者普遍采用多源数据集成策略,将 LLM 与搜索引擎、数据库、文件系统等外部资源互联。然而,异构数据源的协议差异与格式壁垒,往往导致集…

gradio调用多个CSS的HTML页

很多博客介绍的gradio读取html和css比较简单&#xff0c;如果要做很细致的前端页面优化&#xff0c;比如丰富的响应式的cssjs&#xff0c;至少要有html多个css&#xff0c;是暂不能实现的。bootstrap、font-awesome、jquery等 方案一当然是直接更换htmlcss为主的部署方式&#…

【实战ES】实战 Elasticsearch:快速上手与深度实践-2.2.1 Bulk API的正确使用与错误处理

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 Elasticsearch Bulk API 深度实践&#xff1a;性能调优与容错设计1. Bulk API 核心机制解析1.1 批量写入原理剖析1.1.1 各阶段性能瓶颈 2. 高性能批量写入实践2.1 客户端最佳…

基于ESP32和TinyUSB实现虚拟U盘功能的完整指南

基于ESP32和TinyUSB实现虚拟U盘功能的完整指南 基于ESP32和TinyUSB实现虚拟U盘功能的完整指南 摘要引言安装 esp_tinyusb 依赖自定义主机电脑卷标USB描述符配置与初始化MSC配置与SD卡初始化 SD卡初始化代码解析 文件目录浏览与任务调度完整代码结论 摘要 本文详细介绍了如何…

C++:泛型算法

​操作数据&#xff0c;而非容器 一、概述 泛型算法&#xff08;Generic Algorithm&#xff09;​ 是 C Standard Template Library (STL) 的核心组成部分&#xff0c;其本质是与容器类型无关的通用操作逻辑。通过模板和迭代器机制&#xff0c;泛型算法能够对任意满足迭代器接…

UE4学习笔记 FPS游戏制作20 重写机器人和玩家死亡 切换相机和模型

定义父类中的死亡方法 在父类中定义OnDie方法&#xff0c;不需要实现&#xff0c;由子类实现各自的死亡逻辑 新建一个Die方法&#xff0c;处理公共的死亡逻辑 Die的实现&#xff1a; 以前的分离控制现在要延迟做&#xff0c;如果分离了控制器&#xff0c;就无法再获取到玩家的…

AI小白的第七天:必要的数学知识(概率)

概率 Probability 1. 概率的定义 概率是一个介于 0 和 1 之间的数&#xff0c;表示某个事件发生的可能性&#xff1a; 0&#xff1a;事件不可能发生。1&#xff1a;事件必然发生。0 到 1 之间&#xff1a;事件发生的可能性大小。 例如&#xff0c;掷一枚公平的硬币&#xf…

Occlum 是一个内存安全的、支持多进程的 library OS,特别适用于 Intel SGX。

前言 大家好&#xff0c;我是老马。 sofastack 其实出来很久了&#xff0c;第一次应该是在 2022 年左右开始关注&#xff0c;但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFABoot-00-sofaboot 概览 SOFABoot-01-蚂蚁金服开源的 s…