当前位置: 首页 > news >正文

数据结构(C):二叉树前中后序和层序详解及代码实现及深度刨析

目录

🌞0.前言

🚈1.二叉树链式结构的代码是实现

🚈2.二叉树的遍历及代码实现和深度刨析代码

🚝2.1前序遍历

✈️2.1.1前序遍历的理解

✈️2.1.2前序代码的实现

✈️2.1.3前序代码的深度解剖

🚝2.2中序遍历

✈️2.2.1中序遍历的理解

✈️2.2.中序代码的实现

🚝2.3后序遍历

✈️2.3.1后序遍历的理解

✈️2.3.2后序代码的实现

🚈3.层序遍历

🚝 3.1层序遍历的代码实现

🚈4.二叉树学习的相关建议和方法

✍5.结束语


🌞0.前言

言C之言,聊C之识,以C会友,共向远方。各位博友的各位你们好啊,这里是持续分享数据结构知识的小赵同学,今天要分享的数据结构知识是二叉树的前中后序和层序,在这一章,小赵将会向大家展开聊聊二叉树的前中后序和层序的相关知识。✊

🚈1.二叉树链式结构的代码是实现

有了前面几篇博客的加持,我们也算是对于二叉树有了清晰的认识,在这样的情况下,我们就可以尝试用链表去实现我们的二叉树了。

如这样一棵二叉树

我们该如何实现呢,其实实现起来也容易,就是创建每一个节点,然后用手动把他们连起来,其的操作方法和我们之前的链表很像。

typedef int treenode;
typedef struct BTNode
{int x;//本身存储的数据struct BTNode*left;//左孩子struct BTNode* right;//右孩子
}BTNode;BTNode* BuyNode(int a)//生成一个节点
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));//申请一个空间if (newnode == NULL){perror("malloc failed");return;}newnode->left = NULL;//先默认左右孩子为空newnode->right = NULL;newnode->x = a;return newnode;//返回节点
}
BTNode* CreateBT()
{BTNode* node1 = BuyNode(5);//生成需要的节点BTNode* node2 = BuyNode(6);BTNode* node3 = BuyNode(7);BTNode* node4 = BuyNode(1);BTNode* node5 = BuyNode(3);BTNode* node6 = BuyNode(8);BTNode* node7 = BuyNode(5);node1->left = node2;//将节点连起来node1->right = node3;node2->left = node4;node2->right = node5;node3->left = node6;node3->right = node7;return node1;
}
int main()
{BTNode* phead = CreateBT();}

这样我们就可以建立我们的链表了。 

🚈2.二叉树的遍历及代码实现和深度刨析代码

那我们有了一棵树,现在我想遍历这个树的数据怎么办呢?这个时候我们就提出了三种遍历方式叫前中后序遍历。

🚝2.1前序遍历

✈️2.1.1前序遍历的理解

那么前序是怎么遍历的呢?叫根左右,什么叫做根左右呢?就是先遍历一棵树的根部,再遍历这棵树的左子树,左子树遍历完了,再遍历这棵树的右子树。

 那么对于像我们这棵树的遍历顺序是什么呢?如果用前序遍历的话是5613785

相信这个答案很多人会很惊讶,为什么会是这样呢?其实小赵一开始也是这样,但只要一步步弄懂了,就会觉得不难了。

首先我们遍历这棵树的根部就是5,这个大家应该都没问题。

 

那么接下来我们要干嘛要遍历左子树对不对,那我们就进入左子树进行遍历。这个时候的遍历方法其实就是把它的左子树单独看。

 

好了那么我们怎么遍历左子树呢?还是那个方法啊,先遍历根,根是谁,6,那么5之后就是6。然后我们接着遍历这颗树的左子树,又是根开始就是1,那么6之后就是1。下面遍历1的左子树,我们发现1的左子树没了,那接着遍历右子数,我们发现1的右子树也没了,这个时候我们1这棵子树已经遍历完成了。我们发现对于6来说,1的这棵左子树已经遍历完成了,那就遍历6的右子数,也就是3,等到3也遍历完了,那么6的左右子数就遍历完了,对于最上面的5的根来说,它的左子树就遍历完成了,接着去遍历右子数,还是按照我们遍历左子树的方法去进行遍历。

✈️2.1.2前序代码的实现

void PreOrder(BTNode* root)
{if (root==NULL)//看这个节点是否是空节点{return;//是返回}printf("%d", root->x);//遇到根打印PreOrder(root->left);//遍历左子树PreOrder(root->right);//遍历右子树
}

 看到这个代码的,我的头一阵晕,因为我怎么都无法想象一个这么大的遍历最后实现的代码会这么短。我也很难去进入到这个递归代码的里面去找寻原因,后来我发现一个方面是我的对于深层次的递归可能脑子有点记不住前面的递归,还有一个方面就是我不知道这个函数的返回问题。最终我也是在b站,百度上找到了解决这个问题的办法,这个办法就是递归展开图。

✈️2.1.3前序代码的深度解剖

什么叫递归展开图呢?其实就是把隐藏的代码表示出来,因为我们要无数次的重新进入这个函数,那不如就把每一次的递归场景画出来。

这里呢小赵就演示了一下左子树的递归展开图的方式,下面的中序后序也是一样的 

所以下面小赵可能就不再进行这样的演示,大家可以自行操作,这个的操作软件就是我们电脑上都有的画图软件。

大家可以先将我们的代码截屏一下,然后在画图软件里面用ctrl+v就可以出现很多一样的图了。然后自己用上面的工具去操作还是非常好用的。

🚝2.2中序遍历

✈️2.2.1中序遍历的理解

那么中序是怎么遍历的呢?叫左根右,什么叫做左根右呢?相信大家也都猜出来了就是先遍历一棵树的左子树,遍历完了左子树,再遍历这棵树的根,最后遍历右子树。

其实如果前序能理解这个也大差不差,但是这里有一个点要注意其实和上面的前序遍历一样只有访问根才能接触到数据,遍历其实是接触不到的。

例如这个图如果按中序先遍历左树,5就不是第一个。而要遍历5的左子树。

 那么其的访问方式其实和我们之前遍历是很像的,我们一直遍历一棵树的左子树,知道其中一棵的左子树遍历没了,我们就开始访问这棵树的根节点,这个时候对我们这个图来说就是1作为第一个数据

那么我们最后中序遍历的结果其实是1635875

✈️2.2.中序代码的实现

中序代码的实现

void InOrder(BTNode* root)
{if (root == NULL)//看看这个节点是不是空节点{return;}InOrder(root->left);//遍历左子树printf("%d", root->x);//访问根节点InOrder(root->right);//遍历右子树
}

然后这个代码小赵也是非常推荐大家去按照小赵上面的方法去画递归展开图,虽然初期递归展开图很费时间和经历但对于你去理解二叉树的前中后序是绝对非常有帮助的。 

🚝2.3后序遍历

✈️2.3.1后序遍历的理解

后序遍历就是左右根(其实这个时候我们发现记忆前序中序和后序不难只需要想根节点的位置就行。)

 然后按这种方式遍历,我们会发现最上面的5是最后遍历的,其实相对于任何一棵树都是,根是最后遍历的,因为它必须先遍历左子树和右子树才能访问到根节点。’

然后后序遍历的结果是:1368575

✈️2.3.2后序代码的实现

void PostOrder(BTNode* root)
{if (root == NULL)//看看这个节点是不是空节点{return;}PostOrder(root->left);//遍历左子树PostOrder(root->right);//遍历右子树printf("%d", root->x);//访问根节点
}

这个也是一样要画画递归展开图。  

🚈3.层序遍历

之所以把层序遍历拿出来聊,是因为我感觉这个东西和前面的前中后序还是不大一样,正如它的名字所言,它是一层一层遍历的,在实现的方法上也不是我们之前的递归。

层序遍历的具体方式如下:

✈️🚝✈️ 3.1层序遍历的代码实现

 那么层序遍历主要使用的是什么方法呢?其实是我们的队列,为什么使用队列呢?因为使用队列有一个好处就是先进先出,我们可以让我们的根节点先进去,然后根据根节点,插入我们的左子树和右子树,然后把根节点数据打印出来,然后在进入下一个阶段,左子树把下面两个带入,自己出去。

那么按这样的顺序,5出来后6,7就会进入,6出去后,1,3就会进入,然后是7进入,就可以完美的完成我们的遍历任务了。

因为这里要用到队列,所以小赵就先把前面的代码拷了过来,各位想要实现列表可以看看前面的文章数据结构(c):队列  http://t.csdnimg.cn/Px3yF ,小赵在里面已经非常详细地说明了其的实现方法,这里唯一要注意的是要把里面存的数据改成我们的节点。

typedef  BTNode* QDataType;
void LevelOrder(Queue* Qphead, BTNode* BTphead)
{QueuePush(Qphead, BTphead);//将根节插入队列中while (!QueueEmpty(Qphead)){if (BTphead == NULL){return;}QueuePush(Qphead, BTphead->left);//将根节点的左右子数插入队列QueuePush(Qphead, BTphead->right);int data = BTphead->x;//拿到该节点的数据QueuePop(Qphead);//在队列中删除该节点printf("%d", data);//打印节点BTphead = QueueFront(Qphead);//拿到下一个节点}
}
int main()
{BTNode* phead = CreateBT();Queue* head = (Queue*)malloc(sizeof(Queue));QueueInit(head);//初始化队列LevelOrder(head, phead);
}

层序遍历的代码会相对好懂一些。各位也可以进入代码中去研究,想每一步是如何走的。

这里用我们的调试功能就能很清晰的知道自己的代码是如何运行的了。 

🚈4.二叉树学习的相关建议和方法

二叉树的学习对于整个编程的学习非常重要,它联系着后面的红黑二叉树等相关知识,也联系着我们的重要算法dfs,bfs,在这一阶段,我们要不断地去画递归展开图,才能真正理解透彻这一段代码,小赵在后面也会出一些与其相关的联系题帮助大家去理解。

这里小赵也是从网上找来了相关的动态图片去帮助大家理解。

✍5.结束语

好了小赵今天的分享就到这里了,如果大家有什么不明白的地方可以在小赵的下方留言哦,同时如果小赵的博客中有什么地方不对也希望得到大家的指点,谢谢各位家人们的支持。你们的支持是小赵创作的动力,加油。

如果觉得文章对你有帮助的话,还请点赞,关注,收藏支持小赵,如有不足还请指点,方便小赵及时改正,感谢大家支持!!!

相关文章:

数据结构(C):二叉树前中后序和层序详解及代码实现及深度刨析

目录 🌞0.前言 🚈1.二叉树链式结构的代码是实现 🚈2.二叉树的遍历及代码实现和深度刨析代码 🚝2.1前序遍历 ✈️2.1.1前序遍历的理解 ✈️2.1.2前序代码的实现 ✈️2.1.3前序代码的深度解剖 🚝2.2中序遍历 ✈…...

Win11可以安装AutoCAD2007

1、在win11中,安装AutoCAD2007,需要先安装NET组件。否则会提示缺少".net文件" 打开“控制面板”,点击“程序”,点击“程序和功能”,点击“启用或关闭Windows功能”,勾选“.NET FrameWork 3.5”&a…...

C#操作MySQL从入门到精通(14)——汇总数据

前言 我们有时候需要对数据库查询的值进行一些处理,比如求平均值等操作,本文就是详细讲解这些用法,本文测试使用的数据库数据如下: 1、求平均值 求所有student_age 列的平均值 string sql = string.Empty; if (radioButton_AVG.Checked) {sql = “select AVG( student_…...

【设计模式深度剖析】【2】【行为型】【命令模式】| 以打开文件按钮、宏命令、图形移动与撤销为例加深理解

👈️上一篇:模板方法模式 | 下一篇:职责链模式👉️ 设计模式-专栏👈️ 文章目录 命令模式定义英文原话直译如何理解呢? 四个角色1. Command(命令接口)2. ConcreteCommand(具体命令类&…...

【随手记】maplotlib.use函数设置图像的呈现方式

matplotlib.use() 函数用于设置 matplotlib 的后端,这会影响图形的呈现方式。不同的后端适用于不同的环境和需求。下面列出一些常用的后端及其描述: 常见后端参数 Agg: 参数:agg描述:基于Anti-Grain Geometry的后端,适…...

LLVM Cpu0 新后端 系列课程总结

想好好熟悉一下llvm开发一个新后端都要干什么,于是参考了老师的系列文章: LLVM 后端实践笔记 代码在这里(还没来得及准备,先用网盘暂存一下): 链接: https://pan.baidu.com/s/1yLAtXs9XwtyEzYSlDCSlqw?…...

【云原生】Kubernetes----RBAC用户资源权限

目录 引言 一、Kubernetes安全机制概述 二、认证机制 (一)认证方式 1.HTTPS证书认证 1.1 证书颁发 1.2 config文件 1.3 认证类型 1.4 Service Account 1.4.1 作用 1.4.2 包含内容 1.4.3 与Secret的关系 2.Bearer Tokens 3.基本认证 三、鉴…...

ORA-01652 表空间不够解决方案

前章:出现表空间不足不要手动强制删除对应数据文件存储目录下的DBF文件,需要用SQL语句进行数据文件的DROP,否则会导致ORA-01033报错,因为我没有开启数据库的归档所以不能通过RECOVER的形式找回数据文件最后只能重装本地ORACLE。 …...

亚马逊 AWS 视频转码功能、AWS Elemental MediaConvert 中创建和管理转码作业

上传的视频需要转码成不同的编码, 可以直接在 AWS Elemental MediaConvert 中创建和管理转码作业 AWS Elemental MediaConvert 中创建和管理转码作业 /*** 视频转码* return bool* author wzb* data 2024/5/30*/function videoTranscode(&$data){$fileId $data[id] ?? …...

RocketMQ可视化界面安装

RocketMQ可视化界面安装 **起因:**访问rocketmq-externals项目的git地址,下载了源码,在目录中并没有找到rocketmq-console文件夹。 git下面文档提示rocketMQ的仪表板转移到了新的项目中,点击仪表板到新项目地址; 下载…...

【ffmpeg】本地格式转换 mp4转wav||裁剪mp4

个人感受:太爽了!!!(可能用惯了转换网站和无良的转换软件) ———— 使用FFmpeg把mp4文件转换为WAV文件 - 简书 (jianshu.com) FFMPEG 视频分割和合并 - 简书 (jianshu.com) ———— 示例 ffmpeg -i …...

基于Django+MySQL的智慧校园系统

此项目基于Django MySQL HTML CSS JS jQuery bootstrap实现的功能有 学生管理部门管理代办清单管理校园论坛校园医疗服务校园看点校园生活助手常用功能入口 1. 一些注意点 1. 页面body会自动有一些边界距&#xff0c;处理方法&#xff1a; <head><style>b…...

Linux基础指令(一)

前言 Linux基础指令主要学习&#xff1a;对目录、文件、压缩包、匹配查找&#xff0c;权限等操作 第一次接触ubuntu需要知道的基本知识 sudo passwd root 先给root用户设置密码 su root 切换到root用户 su zhangsan …...

三极管十大品牌

三极管十大品牌-三极管品牌-晶体三极管哪个品牌好-Maigoo品牌榜...

需求记录(共享元素)

MainActivity1 列表展示&#xff0c;使用共享元素完成页面间的切换 package com.example.animactivity;import android.annotation.SuppressLint; import android.app.ActivityOptions; import android.content.Intent; import android.os.Build; import android.os.Bundle; i…...

.Net 使用 MongoDB

安装nuget包 MongoDB.Driver 简单代码 using MongoDB.Bson; using MongoDB.Driver; using System.Buffers; using System.Collections.Concurrent; using System.Diagnostics;namespace ConsoleApp4 {internal class Program{static void Main(string[] args){var client = ne…...

【TensorFlow深度学习】值函数估计:蒙特卡洛方法与TD学习

值函数估计&#xff1a;蒙特卡洛方法与TD学习 值函数估计&#xff1a;蒙特卡洛方法与TD学习的深度探索蒙特卡洛方法时序差分学习(TD)Python代码示例结论 值函数估计&#xff1a;蒙特卡洛方法与TD学习的深度探索 在强化学习的奇妙世界里&#xff0c;值函数估计扮演着至关重要的…...

成功解决ModuleNotFoundError: No module named ‘cv2’

成功解决ModuleNotFoundError: No module named ‘cv2’ &#x1f308; 欢迎莅临我的个人主页&#x1f448;这里是我深耕Python编程、机器学习和自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;并乐于分享知识与经验的小天地&#xff01;&#x1f387; &#x1f393;…...

中国蚁剑 安装教程 2024年5月

2024/5/11 中国蚁剑 安装教程 一、下载中国蚁剑的加载器和核心源码&#xff08;两个都要用到&#xff09; github官方下载地址&#xff1a;https://github.com/AntSwordProject/ 参考文档&#xff1a;antSword/README_CN.md at master AntSwordProject/antSword GitHub 核…...

Golang-分离式加载器(传参)AES加密

目录 enc.go 生成: dec.go --执行dec.go...--上线 cs生成个c语言的shellcode. enc.go go run .\enc.go shellcode 生成: --key为公钥. --code为AES加密后的数据, ----此脚本每次运行key和code都会变化. package mainimport ("bytes""crypto/aes"&…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...