java学习之数据结构:四、树(代码补充)

这部分主要是用代码实现有序二叉树、树遍历、删除节点

目录

1.构建有序二叉树

1.1原理

 1.2插入实现

2.广度优先遍历--队列实现

3.深度优先遍历--递归实现

3.1先序遍历

3.2中序遍历

3.3后序遍历

4.删除

4.1删除叶子节点

4.2删除有一棵子树的节点

4.3删除有两棵子树的节点

5.整体代码


1.构建有序二叉树

1.1原理

左边节点值小于父节点,右边节点值大于父节点,看下图

 1.2插入实现

当传入value值时,判断root节点是否为空:空的话建立新节点做root;不空,建立一个中间节点index,然后循环按照插入原理判断插到哪,代码如下:

 public void insert(int value){Node node = new Node(value);if(root==null){root = node;return;}Node index = root;while(true) {if(index.value>value) {//要插入的节点值小if(index.left==null) {//插入index.left=node;return;}index=index.left;}else{//要插入的节点值大if(index.right==null){index.right=node;return;}index=index.right;}}

2.广度优先遍历--队列实现

广度优先遍历就是层次遍历,使用队列实现。当队列中进入一个新节点,输出后就找这个节点的左右孩子入队。

代码如下:

    public void levelOrder() {Queue<Node> queue = new LinkedList<Node>();if(root!=null) {queue.add(root);}Node index;while (!queue.isEmpty()){index = queue.poll();System.out.print(index.value+Messages.getString("BinaryTree.0")); //$NON-NLS-1$if(index.left!=null){queue.add(index.left);}if(index.right!=null) {queue.add(index.right);}}System.out.println();}

3.深度优先遍历--递归实现

3.1先序遍历

就是根-左-右的顺序,使用递归实现,代码如下:

    /** 先序遍历*/public void beforeOrder(Node node){if(node==null) {return;}System.out.print(node.value+Messages.getString("BinaryTree.1"));beforeOrder(node.left);beforeOrder(node.right);}

3.2中序遍历

使用左-根-右顺序

    /** 中序遍历*/public void inOrder(Node node){if(node==null){return;}inOrder(node.left);System.out.print(node.value+Messages.getString("BinaryTree.2")); //$NON-NLS-1$inOrder(node.right);}

3.3后序遍历

使用左-右-根顺序,代码如下:

    /** 后序遍历*/public void afterOrder(Node node) {if(node==null) {return;}afterOrder(node.left);afterOrder(node.right);System.out.print(node.value+Messages.getString("BinaryTree.3")); }

4.删除

删除比较复杂,要分三种情况:

4.1删除叶子节点

  1. 找到目标节点:在二叉搜索树中定位要删除的目标节点target 。
  2. 找到父节点:确定target节点的父节点parent 。
  3. 判断父节点情况
    • 若无父节点,意味着target是根节点,直接将根节点置为null 。
    • 若有父节点,判断targetparent的左子还是右子:是左子就执行parent.left = null ;是右子就执行parent.right = null 。

需要额外写一个函数来寻找父节点,代码如下:

    /*** 找目标值的父节点*/public Node searchParent(int value) {if(root==null) {return null;}Node index = root;while (index!=null) {if((index.left!=null&&index.left.value==value)||(index.right!=null&&index.right.value==value)) {return index;}else if (index.value>value) {index=index.left;}else {index = index.right;}}return null;}

这部分代码如下:

		if(target.left==null&&target.right==null) {//叶子节点//没有父节点if(parent==null) {root=null;return;}//有父节点if(parent.left!=null&&parent.left.value==value) {parent.left=null;}else {parent.right=null;}}

4.2删除有一棵子树的节点

  1. 找到目标节点:确定要删除的节点target 。
  2. 找到父节点:找到target节点的父节点parent 。
  3. 判断父节点和子树情况
    • 若无父节点,即target是根节点,若target有左子树,让根节点指向其左子树(root = root.left );若有右子树,让根节点指向其右子树(root = root.right )。
    • 若有父节点,先确定targetparent的左子还是右子,再根据target自身有左子树还是右子树,调整parent相应子树指针(如parent.left = target.left 或parent.right = target.right )。

代码如下:

			//有一棵子树的节点//没有父节点if(parent==null) {//目标节点有左子树还是右子树if(target.left!=null) {root = root.left;}else {root=root.right;}return;}//有父节点//判断目标节点是父节点的左孩子还是右孩子if(parent.left!=null&&parent.left.value==value) {//左孩子//目标节点有左子树还是右子树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;}}

4.3删除有两棵子树的节点

  1. 找到目标节点:定位要删除的节点target 。
  2. 替换节点选择:获取target左子树的最大值节点或者右子树的最小值节点作为替换节点。
  3. 删除目标节点:用选定的替换节点替代target节点的位置 ,并处理好相关子树连接关系(如parent.left = target.right 或parent.right = target.left 等)。

需要额外写一个判断最小值的函数:

	/*** 找树当中的最小值*/public int min(Node node) {Node index = node;while(index.left!=null) {index=index.left;}return index.value;}

 

代码如下:

 if(target.left!=null&&target.right!=null) {//有两棵子树的节点int minVal = min(target.right);delete(minVal);target.value = minVal;}

5.整体代码

代码如下:

package com.qcby.树;import java.util.LinkedList;
import java.util.Queue;public class BinaryTree {Node root;/*** 插入*/public void insert(int value){Node node = new Node(value);if(root==null){root = node;return;}Node index = root;while(true) {if(index.value>value) {//要插入的节点值小if(index.left==null) {//插入index.left=node;return;}index=index.left;}else{//要插入的节点值大if(index.right==null){index.right=node;return;}index=index.right;}}}/** 广度优先遍历*/public void levelOrder() {Queue<Node> queue = new LinkedList<Node>();if(root!=null) {queue.add(root);}Node index;while (!queue.isEmpty()){index = queue.poll();System.out.print(index.value+Messages.getString("BinaryTree.0")); //$NON-NLS-1$if(index.left!=null){queue.add(index.left);}if(index.right!=null) {queue.add(index.right);}}System.out.println();}/** 先序遍历*/public void beforeOrder(Node node){if(node==null) {return;}System.out.print(node.value+Messages.getString("BinaryTree.1")); //$NON-NLS-1$beforeOrder(node.left);beforeOrder(node.right);}/** 中序遍历*/public void inOrder(Node node){if(node==null){return;}inOrder(node.left);System.out.print(node.value+Messages.getString("BinaryTree.2")); //$NON-NLS-1$inOrder(node.right);}/** 后序遍历*/public void afterOrder(Node node) {if(node==null) {return;}afterOrder(node.left);afterOrder(node.right);System.out.print(node.value+Messages.getString("BinaryTree.3")); //$NON-NLS-1$}/** 查找*/public Node search(int value) {if(root==null) {return null;}Node index = root;while (index!=null) {if(index.value==value){return index;}else if(index.value>value) {index = index.left;}else {index=index.right;}}return null;}/*** 找目标值的父节点*/public Node searchParent(int value) {if(root==null) {return null;}Node index = root;while (index!=null) {if((index.left!=null&&index.left.value==value)||(index.right!=null&&index.right.value==value)) {return index;}else if (index.value>value) {index=index.left;}else {index = index.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 value){if(root==null) {System.out.println(Messages.getString("BinaryTree.4")); return;}//找目标节点Node target = search(value);if(target==null) {System.out.println(Messages.getString("BinaryTree.5")); return;}//找目标节点的父节点Node parent = searchParent(value);//三种情况,分情况讨论if(target.left==null&&target.right==null) {//叶子节点//没有父节点if(parent==null) {root=null;return;}//有父节点if(parent.left!=null&&parent.left.value==value) {parent.left=null;}else {parent.right=null;}}else if(target.left!=null&&target.right!=null) {//有两棵子树的节点int minVal = min(target.right);delete(minVal);target.value = minVal;}else {//有一棵子树的节点//没有父节点if(parent==null) {//目标节点有左子树还是右子树if(target.left!=null) {root = root.left;}else {root=root.right;}return;}//有父节点//判断目标节点是父节点的左孩子还是右孩子if(parent.left!=null&&parent.left.value==value) {//左孩子//目标节点有左子树还是右子树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;}}}}@Overridepublic String toString() {return "BinaryTree [root=" + root + "]";}}

 

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

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

相关文章

架构进阶:什么是数据架构,如何理解数据架构?(华为)

数据架构是企业架构的重要组成部分,DAMA、IBM 及国内大厂对其定义各有侧重。它包含数据资产目录、数据标准、数据模型和数据分布四个组件。数据资产目录可梳理企业数据资产,数据标准统一数据含义和规则,数据模型反映业务对象关联关系,数据分布呈现数据流动情况。数据架构是…

Unity SpriteEditor(精灵图片编辑器)

&#x1f3c6; 个人愚见&#xff0c;没事写写笔记 &#x1f3c6;《博客内容》&#xff1a;Unity3D开发内容 &#x1f3c6;&#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f50e;SpriteEditor&#xff1a; 精灵图片编辑器 &#x1f4cc;用于编辑2D游戏开发中使用的Sp…

【网络原理】从零开始深入理解HTTP的报文格式(一)

本篇博客给大家带来的是网络HTTP协议的知识点, 重点介绍HTTP的报文格式. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f68…

ElasticSearch深入解析(九):Object、Nested、Flattened类型

文章目录 一、Object 类型&#xff1a;默认的嵌套对象处理方式核心原理典型场景关键限制 二、Nested 类型&#xff1a;解决嵌套数组的关联查询核心原理典型场景使用示例注意事项 三、Join 类型&#xff1a;跨文档的父子关联核心原理典型场景使用示例注意事项 四、Flattened 类型…

36、C#中的⽅法声明参数关键字params,ref,out的意义及⽤法

在C#中&#xff0c;params、ref 和 out 是方法声明中用于修饰参数的关键字&#xff0c;它们各自有不同的用途和语义。以下是它们的详细说明和用法&#xff1a; 1、 params 关键字 意义 params 允许方法接受可变数量的参数&#xff0c;这些参数会被编译为一个数组。适用于参数…

【大模型实战篇】华为信创环境采用vllm部署QwQ-32B模型

1. 背景 本文分享在华为昇腾机器上部署QwQ-32B模型的实践。 首先华为自己是提供了一套在信创机器&#xff08;NPU&#xff09;上部署模型的方案【1】&#xff0c;但是部署之后&#xff0c;测试发现会有输出截断的现象。QwQ-32B本身是支持128k的最大上下文长度&#xff0c;定位…

前端面经-VUE3篇(二)--vue3基础知识(二)计算属性(computed)、监听属性(Watch)

一、计算属性(computed) 计算属性&#xff08;Computed Properties&#xff09;是 Vue 中一种特殊的响应式数据&#xff0c;它能基于已有的响应式数据动态计算出新的数据。 计算属性有以下特性&#xff1a; 自动缓存&#xff1a;只有当它依赖的响应式数据发生变化时&#xff…

[预备知识] 5. 优化理论(一)

优化理论 梯度下降&#xff08;Gradient Descent&#xff09; 数学原理与可视化 梯度下降是优化领域的基石算法&#xff0c;其核心思想是沿负梯度方向迭代更新参数。数学表达式为&#xff1a; θ t 1 θ t − α ∇ θ J ( θ t ) \theta_{t1} \theta_t - \alpha \nabla…

大模型微调Fine-tuning:从概念到实践的全面解析

目录 引言 一、什么是大模型微调&#xff1f; 1.1 预训练与微调的区别 1.2 微调的技术演进 二、为什么需要微调&#xff1f; 2.1 解决大模型的固有局限 2.2 微调的优势 三、主流微调方法 3.1 全参数微调 3.2 参数高效微调&#xff08;PEFT&#xff09; 四、微调实践指…

Docker 使用下 (二)

Docker 使用下 &#xff08;二&#xff09; 文章目录 Docker 使用下 &#xff08;二&#xff09;前言一、初识Docker1.1 、Docker概述1.2 、Docker的历史1.3 、Docker解决了什么问题1.4 、Docker 的优点1.5 、Docker的架构图 二、镜像三、容器四、数据卷4.1、数据卷的概念4.2 、…

洛谷P12238 [蓝桥杯 2023 国 Java A] 单词分类

[Problem Discription] \color{blue}{\texttt{[Problem Discription]}} [Problem Discription] Copy from luogu. [Analysis] \color{blue}{\texttt{[Analysis]}} [Analysis] 既然都是字符串前缀的问题了&#xff0c;那当然首先就应该想到 Trie \text{Trie} Trie 树。 我们可…

pta作业中有启发性的程序题

1 【知识点】&#xff1a;多态 函数接口定义&#xff1a; 以Student为基类&#xff0c;构建GroupA, GroupB和GroupC三个类 裁判测试程序样例&#xff1a; #include<iostream> #include <string> using namespace std;/* 请在这里填写答案 */int main() {const …

Scrapy框架之CrawlSpider爬虫 实战 详解

CrawlSpider 是 Scrapy 框架中一个非常实用的爬虫基类&#xff0c;它继承自 Spider 类&#xff0c;主要用于实现基于规则的网页爬取。相较于普通的 Spider 类&#xff0c;CrawlSpider 可以根据预定义的规则自动跟进页面中的链接&#xff0c;从而实现更高效、更灵活的爬取。 Scr…

Glide 如何加载远程 Base64 图片

最近有个需求&#xff0c;后端给出的图片地址并不是正常的 URL&#xff0c;而且需要一个接口去请求&#xff0c;但是返回的是 base64 数据流。这里不关心为啥要这么多&#xff0c;原因有很多&#xff0c;可能是系统的问题&#xff0c;也可能是能力问题。当然作为我们 Android 程…

004-nlohmann/json 快速认识-C++开源库108杰

了解 nlohmann/json 的特点&#xff1b;理解编程中 “数据战场”划分的概念&#xff1b;迅速上手多种方式构建一个JSON对象&#xff1b; 1 特点与安装 nlohmann/json 是一个在 github 长期霸占 “JSON” 热搜版第1的CJSON处理库。它的最大优点是与 C 标准库的容器数据&#xf…

#基础Machine Learning 算法(上)

机器学习算法的分类 机器学习算法大致可以分为三类&#xff1a; 监督学习算法 (Supervised Algorithms&#xff09;:在监督学习训练过程中&#xff0c;可以由训练数据集学到或建立一个模式&#xff08;函数 / learning model&#xff09;&#xff0c;并依此模式推测新的实例。…

正弦波、方波、三角波和锯齿波信号发生器——Multisim电路仿真

目录 Multisim使用教程说明链接 一、正弦波信号发生电路 1.1正弦波发生电路 电路组成 工作原理 振荡频率 1.2 正弦波发生电路仿真分析 工程文件链接 二、方波信号发生电路 2.1 方波发生电路可调频率 工作原理 详细过程 2.2 方波发生电路可调频率/可调占空比 调节占空比 方波产生…

【AND-OR-~OR锁存器设计】2022-8-31

缘由锁存器11111111111-硬件开发-CSDN问答 重置1&#xff0c;不论输入什么&#xff0c;输出都为0&#xff1b; 重置0&#xff0c;输入1就锁住1 此时输入再次变为0&#xff0c;输出不变&#xff0c;为锁住。

力扣-字符串-468 检查ip

思路 考察字符串的使用&#xff0c;还有对所有边界条件的检查 spilt&#xff08;“\.”&#xff09;&#xff0c;toCharArray&#xff0c;Integer.parseInt() 代码 class Solution {boolean checkIpv4Segment(String str){if(str.length() 0 || str.length() > 4) retur…

BC8 十六进制转十进制

题目&#xff1a;BC8 十六进制转十进制 描述 BoBo写了一个十六进制整数ABCDEF&#xff0c;他问KiKi对应的十进制整数是多少。 输入描述&#xff1a; 无 输出描述&#xff1a; 十六进制整数ABCDEF对应的十进制整数&#xff0c;所占域宽为15。 备注&#xff1a; printf可以使用…