二叉树-------前,中,后序遍历 + 前,中,后序查找+删除节点 (java详解)

目录

提要:

 创建一个简单的二叉树:

二叉树的前中后序遍历:

二叉树的前序遍历:

二叉树的中序遍历: 

二叉树的后续遍历:

小结: 

二叉树的前中后续查找:

二叉树的前序查找:

二叉树的中序查找:

二叉树的后续查找: 

代码实现:

二叉树节点删除操作:

思路与约定:

代码实现:

最后,完整代码:


提要:

 二叉树的遍历是指按某条搜索路径访问树中的每个结点,使得每个结点均被访问一次,而且仅能访问一次(说明不可二次访问,一遍而过)。遍历一颗二叉树便要决定对根结点N、左子树L和右子树的访问顺序。 二叉树常的的遍历方法有前序遍历(NLR)、中序遍历(LNR)和后序遍历(LRN)三种遍历算法,其中 “序” 指的是根结点在何时被访问。

遍历大致过程:

前序遍历:根结点 ---> 左子树 ---> 右子树

中序遍历:左子树---> 根结点 ---> 右子树

后序遍历:左子树 ---> 右子树 ---> 根结点

--------------------------------------------------------------------------------------------------------------------------------

 创建一个简单的二叉树:

二叉树的存储结构分为:顺序存储和类似于链表的链式存储,这里我们学习链式存储的方式, 简单枚举一棵二叉树。

用孩子表示法创建一颗二叉树:

//孩子表示法
class KunBinaryTree{//数据域public int no;//序号public String name;//姓名public KunBinaryTree left;//左孩子的引用,常常代表左孩子为根的整棵左子树public KunBinaryTree right;//右孩子的引用,常常代表右孩子为根的整棵右子树//构造方法public KunBinaryTree(int no,String name){super();this.no = no;this.name = name;}
}
public class TestBinaryTree {public static void main(String[] args){//对象实例化KunBinaryTree root = new KunBinaryTree(1,"唱");KunBinaryTree node1 = new KunBinaryTree(2,"跳");KunBinaryTree node2 = new KunBinaryTree(3,"rap");KunBinaryTree node3 = new KunBinaryTree(4,"篮球");KunBinaryTree node4 = new KunBinaryTree(5,"music");KunBinaryTree node5 = new KunBinaryTree(6,"坤坤");//链接各个节点,使其构成一颗二叉树root.left = node1;root.right = node2;node2.left = node3;node2.right = node4;node4.left = node5;}
}

创建了一颗如图所示的二叉树(一共有6个节点,其中root节点为 “唱”):

 

-------------------------------------------------------------------------------------------------------------------------------- 

二叉树的前中后序遍历:

通过上面的简单介绍,我们可以开始正式学习接下来的操作了

二叉树的前序遍历:

基本思路:

若二叉树为空,什么都不做,否则:

        i、先访问根结点;

        ii、再前序遍历左子树;

        iii、最后前序遍历右子树;

代码实现:

//前序遍历public static void preOrder(KunBinaryTree root){if(root == null){return ;}System.out.print(root.no+" "+root.name+" ");//先访问根preOrder(root.left);//接着左右子树preOrder(root.right);}

函数递归展开图解:

首先,我们从蓝色出发,也就是途中的①,按照先根节点后左右子树的过程进行依次遍历,这里相当于先打印根节点所对应的数据域中的信息后,在接着递归调用左子树,直到为空,回溯后递归调用右子树,直到为空。该树的左子树(总的)调用完后, 开始调用右子树,来到②过程,按照(根-----》左子树---》右子树)的规则继续递归。直到左右子树都为空,返回,也就是③,④过程。从途中可以看出,打印的顺序为:1 唱 2 跳 3 rap 4 篮球 5 music 6 坤坤 

 通过遍历的测试结果也显示,上述过程正确:

 或则用更明了直观的动图解释(图中栗子不为上述栗子,仅做参考,便于理解):

二叉树的中序遍历: 

 基本思路:

二叉树为空,什么也不做,否则:

        i、中序遍历左子树;

        ii、访问根结点;

        iii、中序遍历右子树

代码实现:

 //中序遍历public static void infixOrder(KunBinaryTree root){if(root == null){return ;}infixOrder(root.left);System.out.print(root.no +" "+root.name+" ");infixOrder(root.right);}

 函数递归展开图:

 首先,我们先从红色出发,也就是①,按照(左子树---》根---》右子树)的规则依次遍历,这里相当于从不可在分割的左子树开始从后往前进行打印输出对应信息,与前序遍历基本一致,就是中间根节点的位置变化导致输出顺序的不同。

最终递归结果为(打印顺序为):2 跳 1 唱 4 篮球 3 rap 6 坤坤 5 music 

通过测试也可已看出确实是这样:

 用更直观的动图展示(栗子与上述不同,主要是便于理解其过程):

二叉树的后续遍历:

 基本思路:

若二叉树为空,什么也不做,否则:

        i、后序遍历左子树

        ii、后序遍历右子树

        iii、访问根结点

代码实现:

 //后续遍历public static void postOrder(KunBinaryTree root){if(root == null){return ;}postOrder(root.left);postOrder(root.right);System.out.print(root.no +" "+root.name+" ");}

 函数递归展开图:

首先从①开始,按照(左子树---》右子树---》根)的规则依次遍历,过程与上述类似,不在赘述。递归结果为:2 跳 4 篮球 6 坤坤 5 music 3 rap 1 唱  

测试结果也表明上述结果正确: 

 用更直观的动图演示该过程(栗子与上述不同,主要是便于理解其过程):

小结: 

比较各个遍历的过程 

前序遍历:根结点 ---> 左子树 ---> 右子树

中序遍历:左子树---> 根结点 ---> 右子树

后序遍历:左子树 ---> 右子树 ---> 根结点

我们不难发现,前序遍历的root节点(栗子中也就是"1.唱")一定在遍历结果的首部,二中序遍历的root节点在整个树的中部,在遍历的结果中随树的变化二变化,后续遍历的root节点一定在尾部,利用这个特性,我们可以只知道(前序+中序)或者(后续+中序)或则(前序+后续)的遍历结果还原出该二叉树。

二叉树的前中后续查找:

 有了前中后续遍历的实现,我们接着就能实现查找过程,这是基于遍历来实现的

二叉树的前序查找:

基本思路:

1.先判断当前节点的no(序号)是否等于要查找的

2.如果是相等的,则返回当前节点

3.如果不等,则判断当前节点的左右子节点是否为空,如果不为空,则递归前序查找

4.如果左递归前序查找找到节点,则返回,否则继续判断当前节点的左右子节点是否为空,如果不为空,则继续右递归前序查找

代码实现:

//前序查找public static int count1 = 0;//用于记录递归查找的次数public static KunBinaryTree preOrderSearch(KunBinaryTree root,int no){++count1;if(root.no == no){return root;}KunBinaryTree resNode = null;if(root.left != null){resNode = preOrderSearch(root.left,no);}if(resNode != null){return resNode;}if(root.right != null){resNode = preOrderSearch(root.right,no);}return resNode;}

按照上述的遍历结果我们可以知道,一共进行了6次遍历,(咱们这里查找数字6)那么前序查找遍历的次数为6(即count1=6):

测试结果:

 

二叉树的中序查找:

 基本思路:

1.判断当前节点的左右子节点是否为空,如果不为空,则递归中序查找

2.如果找到,则返回,若果没有找到,就和当前节点比较,如果是则返回当前节点,否则继续进行右递归的中序查找

3.右递归中序查找,找到就返回,否则返回null

代码实现:

//中序查找public static int count2 = 0;//记录中序查找次数public static KunBinaryTree infixOrderSearch(KunBinaryTree root,int no){KunBinaryTree resNode = null;if(root.left != null){resNode = infixOrderSearch(root.left,no);}if(resNode != null){return resNode;}++count2;if(root.no == no){return root;}if(root.right != null){resNode = infixOrderSearch(root.right,no);}return resNode;}

按照上述的遍历结果我们可以知道,一共进行了6次遍历,(咱们这里查找数字6)那么中序查找的遍历次数为5(count2=5):

测试结果:

二叉树的后续查找: 

 基本思路:

1.判断当前节点的左子节点是否为空,如果不为空,则递归后序查找

2.如果找到,就返回,如果没有找到,就判断当前节点的有子节点是否为空,如果不为空,则右递归进行后序查找,如果找到,就返回

3.接着和当前节点进行比较,找到则返回,否则返回null

代码实现:

   //后序查找public static int count3 = 0;//记录后序查找遍历次数public static KunBinaryTree postOrderSearch(KunBinaryTree root,int no){KunBinaryTree resNode = null;if(root.left != null){resNode = postOrderSearch(root.left,no);}if(resNode != null){return resNode;}if(root.right != null){resNode = postOrderSearch(root.right,no);}if(resNode != null){return resNode;}++count3;if(root.no == no){return root;}return resNode;}

按照上述的遍历结果我们可以知道,一共进行了6次遍历,(咱们这里查找数字6)那么后序查找的次数为3(count3=3):

测试结果:

 

二叉树节点删除操作:

 最后,咱么来进行二叉树节点删除的操作

思路与约定:

代码实现:

 //删除节点public static void delTreeNode(KunBinaryTree root,int no){if(root.no == no){root = null;}else{if(root.left != null && root.left.no == no){root.left = null;return ;}if(root.right != null && root.right.no == no){root.right = null;return ;}if(root.left != null){delTreeNode(root.left,no);}if(root.right != null){delTreeNode(root.right,no);}}}

 

这里我们删除4子节点,也就是篮球 

测试结果:

当我们删除3这个子节点时,后面的节点也一并删除了:

 

最后,完整代码:

import java.util.*;class KunBinaryTree{public int no;public String name;public KunBinaryTree left;public KunBinaryTree right;public KunBinaryTree(int no,String name){super();this.no = no;this.name = name;}
}public class BinaryTree {
//前中后序遍历//前序遍历public static void preOrder(KunBinaryTree root){if(root == null){return ;}System.out.print(root.no+" "+root.name+" ");preOrder(root.left);preOrder(root.right);}//中序遍历public static void infixOrder(KunBinaryTree root){if(root == null){return ;}infixOrder(root.left);System.out.print(root.no +" "+root.name+" ");infixOrder(root.right);}//后续遍历public static void postOrder(KunBinaryTree root){if(root == null){return ;}postOrder(root.left);postOrder(root.right);System.out.print(root.no +" "+root.name+" ");}
//前中后序查找//前序查找public static int count1 = 0;//用于记录递归查找的次数public static KunBinaryTree preOrderSearch(KunBinaryTree root,int no){++count1;if(root.no == no){return root;}KunBinaryTree resNode = null;if(root.left != null){resNode = preOrderSearch(root.left,no);}if(resNode != null){return resNode;}if(root.right != null){resNode = preOrderSearch(root.right,no);}return resNode;}//中序查找public static int count2 = 0;//记录中序查找次数public static KunBinaryTree infixOrderSearch(KunBinaryTree root,int no){KunBinaryTree resNode = null;if(root.left != null){resNode = infixOrderSearch(root.left,no);}if(resNode != null){return resNode;}++count2;if(root.no == no){return root;}if(root.right != null){resNode = infixOrderSearch(root.right,no);}return resNode;}//后序查找public static int count3 = 0;//记录后序查找遍历次数public static KunBinaryTree postOrderSearch(KunBinaryTree root,int no){KunBinaryTree resNode = null;if(root.left != null){resNode = postOrderSearch(root.left,no);}if(resNode != null){return resNode;}if(root.right != null){resNode = postOrderSearch(root.right,no);}if(resNode != null){return resNode;}++count3;if(root.no == no){return root;}return resNode;}//删除节点public static void delTreeNode(KunBinaryTree root,int no){if(root.no == no){root = null;}else{if(root.left != null && root.left.no == no){root.left = null;return ;}if(root.right != null && root.right.no == no){root.right = null;return ;}if(root.left != null){delTreeNode(root.left,no);}if(root.right != null){delTreeNode(root.right,no);}}}//测试public static void main(String[] args){Scanner sc = new Scanner(System.in);KunBinaryTree root = new KunBinaryTree(1,"唱");KunBinaryTree node1 = new KunBinaryTree(2,"跳");KunBinaryTree node2 = new KunBinaryTree(3,"rap");KunBinaryTree node3 = new KunBinaryTree(4,"篮球");KunBinaryTree node4 = new KunBinaryTree(5,"music");KunBinaryTree node5 = new KunBinaryTree(6,"坤坤");root.left = node1;root.right = node2;node2.left = node3;node2.right = node4;node4.left = node5;preOrder(root);System.out.println();infixOrder(root);System.out.println();postOrder(root);System.out.println();System.out.print("请输入要查找的数字:");int n = sc.nextInt();KunBinaryTree resNode = postOrderSearch(root,n);System.out.println("一共查找的次数count3:"+count3);if(resNode != null){System.out.printf("找到了,Kun节点 no=%d name=%s",resNode.no,resNode.name);}else{System.out.printf("没有找到Kun节点%d的信息",n);}System.out.println();System.out.print("请输入要删除的子节点:");int n2 = sc.nextInt();System.out.println("删除前:");preOrder(root);System.out.println();System.out.println("删除后:");delTreeNode(root,n2);preOrder(root);}
}

博客到这里也是结束了,制作不易,喜欢的小伙伴可以点赞加关注支持下博主,这对我真的很重要~~

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

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

相关文章

Python 数据可视化之山脊线图 Ridgeline Plots

文章目录 一、前言二、主要内容三、总结 🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 JoyPy 是一个基于 matplotlib pandas 的单功能 Python 包,它的唯一目的是绘制山脊线图 Joyplots(也称为 Ridgeline Plots&…

SpringMVC原理(设计原理+启动原理+工作原理)

文章目录 前言正文一、设计原理1.1 servlet生命周期简述1.2 设计原理小结 二、启动原理2.1 AbstractHandlerMethodMapping 初始化 --RequestMapping注解解析2.2 DispatcherServlet 的初始化2.3 DispatcherServlet#initHandlerMappings(...) 初始化示例说明 三、工作原理 前言 …

python - OSError:错误没有名为 [‘pytorch_model.bin‘

python - OSError:错误没有名为 [‘pytorch_model.bin’] 自己训练的模型存储好了以后 model MT5ForConditionalGeneration.from_pretrained(“ner/best”) 之前还可以跑 现在报错 错误没有名为 [‘pytorch_model.bin’] 还原了一下conda env 把四版变成三版了 …

面试前的准备

面试前的准备 Java程序员校招与社招的区别 校招和社招都是企业招聘形式的一种,只是面向的对象不同。校招 只允许在校生参加,社招理论上是任何人都能参加的(包括在校生)。 但是,无论是社招还是校招,它的难度都取决于你的水平高低。…

Unity SRP 管线【第十讲:SRP/URP 图形API】

Unity 封装的图形API 文章目录 Unity 封装的图形API一、 CommandBuffer 要执行的图形命令列表1. CommandBuffer 属性2. CommandBuffer 常用图形API(方法)(1)设置(2)获取临时纹理 GetTemporaryRT以及释放(3)设置纹理为渲染目标 SetRenderTarget(4)Command…

每日OJ题_递归①_力扣面试题 08.06. 汉诺塔问题

目录 递归算法原理 力扣面试题 08.06. 汉诺塔问题 解析代码 递归算法原理 递归算法个人经验:给定一个任务,相信递归函数一定能解决这个任务,根据任务所需的东西,给出函数参数,然后实现函数内容,最后找出…

Shell 学习笔记(三)-shell变量

Shell 语言是一种动态类型和弱类型语言, 因此,在Shell中无需显示地声明变量, 且变量的类型会根据不同的操作符而发生变化. 静态类型语言: 在程序编译期间就确定变量类型的语言, 如java, C等 动态类型语言: 在程序运行期间才确定变量类型的语言, 如PHP, Python等. 一 shell变量…

Matplotlib初探:认识数据可视化与Matplotlib

Matplotlib初探:认识数据可视化与Matplotlib Fig.1 利用Matplotlib进行数据可视化( 可视化代码见文末) 🌵文章目录🌵 🌳引言🌳🌳一、数据可视化简介🌳🌳二、Matplotlib库简介&#x…

【数学建模】【2024年】【第40届】【MCM/ICM】【B题 搜寻潜水器】【解题思路】

一、题目 (一)赛题原文 2024 MCM Problem A: Resource Availability and Sex Ratios Maritime Cruises Mini-Submarines (MCMS), a company based in Greece, builds submersibles capable of carrying humans to the deepest parts of the ocean. A …

WordPress每天发布60s插件

源码名称:WordPress每天发布60s插件 适用平台:WordPress Wordpress还是比较适合个人博客网站,这个60秒插件适合一些喜欢自动发新闻早报晚报人员。 wordpress一直以来都是建立个人博客网站比较适合的脚手架,非常合适个人使用。 小程序源码就找 源码软件…

【Java数据结构】ArrayList和LinkedList的遍历

一&#xff1a;ArrayList的遍历 import java.util.ArrayList; import java.util.Iterator; import java.util.List;/*** ArrayList的遍历*/ public class Test {public static void main(String[] args) {List<Integer> list new ArrayList<>();list.add(5);list…

如何将 Hexo 部署到 GitHub Pages

引言 在数字时代&#xff0c;拥有个人博客是展示自己想法、分享知识和技能的绝佳方式。Hexo 是一个基于 Node.js 的静态博客生成器&#xff0c;它结合了简洁性和功能性&#xff0c;让我们可以轻松地建立并维护一个博客。而 GitHub Pages 提供了一个免费的平台来托管这些静态网站…

Stable Diffusion主流UI详细介绍

Stable Diffusion目前主流的操作界面有WebUI、ComfyUI以及Fooocus 这里webui和fooocus在人机交互上的逻辑是一样的&#xff0c;fooocus界面更加简洁。 comfyui是在人机交互上是采用流程节点的交互逻辑&#xff0c;和上面略有区别。 界面分别如下&#xff1a; WebUI界面如下 we…

java 调用智谱ai 大模型的完整步骤(国内的 AI 大模型 对话)

要使用java 调用智谱AI的API进行异步调用&#xff0c;您需要遵循以下步骤&#xff1a; 1. **获取API密钥**&#xff1a; - 您需要从智谱AI平台获取一个API密钥&#xff08;API Key&#xff09;&#xff0c;这个密钥将用于所有API请求的身份验证。 2. **SDK源…

品牌之门:概率与潜力的无限延伸

在品牌的世界里&#xff0c;每一个成功的推广都像是打开一扇门&#xff0c;从未知走向已知&#xff0c;从潜在走向显现。这扇门&#xff0c;既是品牌的起点&#xff0c;也是品牌发展的无限可能。 品牌&#xff0c;就像一扇紧闭的门&#xff0c;它静静地矗立在那里&#xff0c;…

fluent脱硝SCR相对标准偏差、氨氮比、截面速度计算

# -*- coding: utf-8 -*- """ Created on Wed Sep 20 20:40:30 2023 联系QQ:3123575367&#xff0c;专业SCR脱硝仿真。 该程序用来处理fluent通过export-solution-ASCII-Space导出的数据&#xff0c;可计算标准偏差SD、相对标准偏差RSD,适用于求解平面的相对均匀…

这种学习单片机的顺序是否合理?

这种学习单片机的顺序是否合理&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「单片机的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01…

单片机学习笔记---DS18B20温度传感器

目录 DS18B20介绍 模拟温度传感器的基本结构 数字温度传感器的应用 引脚及应用电路 DS18B20的原理图 DS18B20内部结构框图 暂存器内部 单总线介绍 单总线电路规范 单总线时序结构 初始化 发送一位 发送一个字节 接收一位 接收一个字节 DS18B20操作流程 指令介…

OpenAI ChatGPT 记忆功能怎么实现?

你的聊天助手现在能“记住”你的对话了&#xff01; 2月14日凌晨&#xff0c;OpenAI宣布正在测试ChatGPT的新功能——记住用户提问内容&#xff0c;并自由控制内存。这意味着&#xff0c;ChatGPT能帮你记住那些重要的聊天内容&#xff0c;让你的对话更流畅、更自然。 想象一下…

高效的工作学习方法

1.康奈尔笔记法 在这里插入图片描述 2. 5W2H法 3. 鱼骨图分析法 4.麦肯锡7步分析法 5.使用TODOLIST 6.使用计划模板&#xff08;年月周&#xff09; 7. 高效的学习方法 成年人的学习特点&#xff1a; 快速了解一个领域方法 沉浸式学习方法&#xff1a; 沉浸学习的判据&am…