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

【数据结构】二叉树链式结构——感受递归的暴力美学

前言:

        在上篇文章【数据结构】二叉树——顺序结构——堆及其实现中,实现了二叉树的顺序结构,使用堆来实现了二叉树这样一个数据结构;现在就来实现而二叉树的链式结构。

一、链式结构

        链式结构,使用链表来表示一颗二叉树,即用链来指示二叉树中元素的逻辑关系。通常的就是链表中每个节点右三个域组成,数据域左右指针域左右指针分别指向该节点的左孩子节点和右孩子节点的存储地址。

        链式结构分为二叉链和三叉链(三叉链比而二叉链多一个指向父节点的指针域)。

这里使用二叉链来实现。

二、二叉树链式结构实现相关功能

在实现之前,先来看一下,具体要实现哪些功能?

        首先就是二叉树的结构,我们使用链表来实现,链表的每一个节点都由数值域和左右指针域组成。

        二叉树链式结构的节点

typedef int TreeDataType;
typedef struct TreeNode
{TreeDataType data;struct TreeNode* left;struct TreeNode* right;
}TreeNode;

        二叉树链式结构如上,接下来再来看一下二叉树链式结构实现的相关功能:

//二叉树的前序排序
int PreOrder(TreeNode* root);
//二叉树的中序排序
int InOrder(TreeNode* root);
//二叉树的后序遍历
int AfterOrter(TreeNode* root);
//二叉树节点个数
int BinaryTreeSize(TreeNode* root);
//二叉树叶子节点个数
int BinaryTreeLeafSize(TreeNode* root);
//二叉树第k层节点个数
int BinaryTreeLevelKSize(TreeNode* root, int k);
//二叉树的深度
int BinaryTreeDepth(TreeNode* root);
//查找二叉树值为x的节点
TreeNode* BinaryTreeFind(TreeNode* root, TreeDataType x);
//层序遍历
void LevelOrder(BTNode* root)
//判断是否为满二叉树
bool BinaryTreeComplete(BTNode* root)
//二叉树的销毁
void TreeDesTroy(TreeNode** root);

        2.1、二叉树前、中、后序遍历

这里,前序、中序和后序遍历什么意思呢,

        说白了,这三种遍历其实就是以对二叉树访问的顺序,来遍历二叉树

这里以前序遍历为例,遍历二叉树

现在有一个这样的二叉树,用前序遍历来访问这颗二叉树(这里访问并输出访问到的数据)

        

首先访问根节点,输出访问到的数据 1 ;再访问左子树

再访问其左子树的根节点,输出访问到的数据  2 ;再接着访问左子树

再访问其左子树的根节点,输出访问到的数据 4 ;再接着访问左子树

此时访问到了空节点,就直接回退,回退到其父节点的函数栈帧,访问父节点的右子树

        访问4这个节点的右子树,也为空,此时节4这个点为根节点的左子树已经访问 结束了,回退到其父节点的函数栈帧,访问其父节点的右子树

        访问2这个节点的右子树,先输出右子树的根节点数据 5 ;再访问根节点5的左子树

        这里节点5的左右节点都为空,这里省略一些过程;此时5这个节点访问结束,回退到2这个节点,而2这个节点右子树访问结束,也已经访问结束了;此时再回退到根节点,访问根节点的右子树。

        此时访问根节点的右子树的根节点,输出访问到的数据 3 ;再接着访问3这个节点的左子树

        这里,3这个节点的左右节点都为空,访问就直接返回,回退到根节点,就说明根节点的右子树访问已经结束,此时二叉树已经变了结束。

        这里前序遍历的输出结果为 1 2 4 5 3

这三个前、中、后序遍历本质上没啥差别,这里直接看实现代码

//二叉树的前序排序
void PreOrder(TreeNode* root)
{if (root == NULL){return;}//输出数据printf("%d ", root->data);//遍历左子树PreOrder(root->left);//遍历右子树PreOrder(root->right);
}
//二叉树的中序排序
void InOrder(TreeNode* root)
{if (root == NULL){return;}//遍历左子树InOrder(root->left);//输出数据printf("%d ", root->data);//遍历右子树InOrder(root->right);
}
//二叉树的后序遍历
void AfterOrter(TreeNode* root)
{if (root == NULL){return;}//遍历左子树AfterOrter(root->left);//遍历右子树AfterOrter(root->right);//输出数据printf("%d ", root->data);
}

        这里我们来测试代码对不对,我们先创建一个二叉树,然后看输出结果是否正确、

TreeNode* BuyNode(TreeDataType x)
{TreeNode* newnode = (TreeNode*)malloc(sizeof(TreeNode));if (newnode == NULL){perror("malloc");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}void test()
{TreeNode* node1 = BuyNode(1);TreeNode* node2 = BuyNode(2);TreeNode* node3 = BuyNode(3);TreeNode* node4 = BuyNode(4);TreeNode* node5 = BuyNode(5);node1->left = node2;node1->right = node3;node2->left = node4;node2->right = node5;//前序遍历PreOrder(node1);printf("\n");//中序遍历InOrder(node1);printf("\n");//后序遍历AfterOrter(node1);printf("\n");
}
int main()
{test();return 0;
}

这里代码没有问题。

        2.2、二叉树节点个数

        这里,二叉树的链式结构我们是使用递归来实现的,那我们该如何去计算二叉树的节点个数呢?

思路:
        遍历二叉树,遍历到空节点就返回0,不是空节点就返回其左子树和右子树节点个数之和再加一

代码如下:

//二叉树节点个数
int BinaryTreeSize(TreeNode* root)
{if (root == NULL){return 0;}return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

        2.3、二叉树叶子结点个数

        所谓叶子节点:就是左右子节点都为空的节点,我们就利用这个特点来判断

思路:

        遍历二叉树,遍历到空节点就返回空;遍历到节点的左右节点都为空,返回1;否则就返回节点的左子树和右子树的叶子结点之和。

代码如下:

//二叉树叶子节点个数
int BinaryTreeLeafSize(TreeNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

        2.4、二叉树第k层节点个数

        求二叉树第k层节点的个数,我们先来看这样的一个图

        通过图我们可以看到,每次向下遍历一层,k-1;当k=1时,正好是第k层

思路:

        遍历二叉树,遍历到空节点就返回 0 ;遍历到k=1时,就返回1;否则就返回该节点左子树和右子树中第k - 1层的节点个数。

这里需要注意,要在判断k=1之前判断节点是否为空。

代码如下:

//二叉树第k层节点个数
int BinaryTreeLevelKSize(TreeNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

        2.5、二叉树的深度

        求二叉树的深度,我们这里是将二叉树的左子树和右子树分开依次遍历的,显然我们不能像上面一样,返回遍历左子树和右子树的和;这里就返回其中最大的。

思路:

        遍历二叉树,遍历到空节点就返回空;定义两个值,记录其节点左子树和右子树的深度再加一;返回其中最大的即可。

理解:这里定义两个值记录其左右子树的深度加一(加一就是记录当前这一层)。

代码如下:

//二叉树的深度
int BinaryTreeDepth(TreeNode* root)
{if (root == NULL){return 0;}int depth_left = BinaryTreeDepth(root->left) + 1;int depth_right = BinaryTreeDepth(root->right) + 1;return (depth_left > depth_right) ? depth_left : depth_right;
}

        2.6、查找二叉树中值为 x 的节点

        查找相对来说就比较简单了,遍历二叉树,为空就返回NULL,值为x就返回该节点的地址,如果遍历过程中函数返回值不为NULL,就证明找到了,直接返回即可。

思路:

        遍历二叉树,遍历到空节点就返回NULL;判断节点的值是否为x,是就返回该节点的地址;不是。就创建指针变量接受其左右子树遍历的结果,如果不为NULL就直接返回该返回值。为空则继续遍历。

代码如下:

//查找二叉树值为x的节点
TreeNode* BinaryTreeFind(TreeNode* root, TreeDataType x)
{if (root == NULL){return NULL;}if (root->data == x){return root;}TreeNode* pleft = BinaryTreeFind(root->left, x);if (pleft)return pleft;TreeNode* pright = BinaryTreeFind(root->right, x);if (pright)return pright;return NULL;
}

到这里,来看一下这些代码是否正确

        对于这样的一个二叉树,代码输出结果都正确。

        2.7、层序遍历

这里层序遍历,我们需要借用队列这样一个数据结构(前面有详细讲解),

大致思路如此:

将根节点数据放入队列中;然后出队列,并且把该节点的左右子节点插入到队列当中。

将1这个节点出队列,再把左右子节点插入到队列当中

再出队头节点,将其左右子节点插入队列当中

依次类推,当队头数据左右子节点为空,就不进插入队列这一操作。

代码如下:

        这里用到了对列相关代码,详细代码在上篇

//层序遍历
//借助数据结构---队列
void LevelOrder(BTNode* root)
{Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){//取队头,打印BTNode* front = QueueFront(&q);printf("%d ", front->data);QueuePop(&q);//队头节点的左右孩子入队列if (front->left)QueuePush(&q, front->left);if (front->right)QueuePush(&q, front->right);}//队列为空QueueDestroy(&q);
}

        2.8、判断二叉树是否为满二叉树

        判断二叉树是否为满二叉树,还是借用队列这样的数据结构,和层序遍历有相似之处;与层序遍历不同的是,这里,即便左右子节点为空,有进行入队列操作;当队头数据为空,就判断队列剩余数据是否都为空,如果都为空,就证明二叉树为满二叉树;否则就不是满二叉树。

代码如下:

//判断二叉树是否为完全二叉树
//---队列
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL){break;}QueuePush(&q, front->left);QueuePush(&q, front->right);}//队列不一定为空while (!QueueEmpty(&q)){BTNode* front = QueueFront(&q);QueuePop(&q);if (front != NULL){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

        2.9、二叉树的销毁

        这里为了测试这些代码,就手动创建了一个二叉树,这些都是动态开辟的空间,养成好习惯,手动释放动态开辟的空间。

这里需要注意的是:使用后序遍历,先是否底层的节点,

代码如下:

// 二叉树销毁
void BinaryTreeDesTroy(TreeNode** root)
{if (*root == NULL){return;}BinaryTreeDesTroy(&((*root)->left));BinaryTreeDesTroy(&((*root)->right));free(*root);*root = NULL;
}

感谢各位大佬支持并指出问题,

                        如果本篇内容对你有帮助,可以一键三连支持以下,感谢支持!!!

相关文章:

【数据结构】二叉树链式结构——感受递归的暴力美学

前言: 在上篇文章【数据结构】二叉树——顺序结构——堆及其实现中,实现了二叉树的顺序结构,使用堆来实现了二叉树这样一个数据结构;现在就来实现而二叉树的链式结构。 一、链式结构 链式结构,使用链表来表示一颗二叉树…...

开始尝试从0写一个项目--后端(三)

器材管理 和员工管理基本一致,就不赘述,展示代码为主 新增器材 表设计: 字段名 数据类型 说明 备注 id bigint 主键 自增 name varchar(32) 器材名字 img varchar(255) 图片 number BIGINT 器材数量 comment VARC…...

2024年7月解决Docker拉取镜像失败的实用方案,亲测有效

在Ubuntu 16.04、Debian 8、CentOS 7系统中,若遇到Docker拉取镜像失败的问题,以下是一些亲测有效的解决方案: 配置加速地址 首先,创建Docker配置目录:sudo mkdir -p /etc/docker然后,编辑daemon.json文件…...

基于内容的音乐推荐网站/基于ssm的音乐推荐系统/基于协同过滤推荐的音乐网站/基于vue的音乐平台

获取源码联系方式请查看文末🍅 摘 要 随着信息化时代的到来,系统管理都趋向于智能化、系统化,音乐推荐网站也不例外,但目前国内的有些公司仍然都使用人工管理,公司规模越来越大,同时信息量也越来越庞大&…...

STM32智能工业监控系统教程

目录 引言环境准备智能工业监控系统基础代码实现:实现智能工业监控系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景:工业监控与优化问题解决方案与优化收尾与总结 1. 引言 智能工业监控系统通…...

WEB渗透Web突破篇-SQL注入(MYSQL)

注释符 # -- 注意这里有个空格 /* hello */ /*! hello */ /*!32302 10*/ MYSQL version 3.23.02联合查询 得到列数 order by或group by 不断增加数字,直到得到报错响应 1 ORDER BY 1-- #True 1 ORDER BY 2-- #True 1 ORDER BY 3-- #True 1 ORDER BY 4-- #Fal…...

PDF解锁网站

https://smallpdf.com/cn/unlock-pdfhttps://smallpdf.com/cn/unlock-pdfhttps://www.freemypdf.comhttps://www.freemypdf.com...

【Redis】主从复制分析-基础

1 主从节点运行数据的存储 在主从复制中, 对于主节点, 从节点就是自身的一个客户端, 所以和普通的客户端一样, 会被组织为一个 client 的结构体。 typedef struct client {// 省略 } client;同时无论是从节点, 还是主节点, 在运行中的数据都存放在一个 redisServer 的结构体中…...

Transformer自然语言处理实战pdf阅读

一.第一章 欢迎来到transformer的世界 1.解码器-编码器框架 在Transformer出现之前,NLP的最新技术是LSTM等循环架构。这些架 构通过在神经网络连接使用反馈循环,允许信息从一步传播到另一 步,使其成为对文本等序列数据进行建模的理想选择。如…...

Python 高阶语法

前言: 我们通过上篇文章学习了Python的基础语法,接下来我们来学习Python的高阶语法 1.初识对象 在Python中我们可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的 面向对象包含 3 大主要特性:  封装  继承 …...

开始尝试从0写一个项目--前端(三)

器材管理板块 添加器材管理导航 src\views\home\Home.vue src\router\index.js src\views\equipment\Equipment.vue <template><div>hello!</div></template> 测试 搜索导航分页查询 src\views\equipment\Equipment.vue <template><div&…...

Visual stdio code 运行C项目环境搭建

参考 [1]VS Code 配置 C/C 编程运行环境&#xff08;保姆级教程&#xff09;_visual studio code c配置-CSDN博客 [2]最新VS code配置C/C环境(tasks.json, launch.json,c_cpp_properties.json)及运行多个文件、配置Cmake_vscode launch.json如何配置-CSDN博客 先装visual stdi…...

免杀笔记 -->API的整理Shellcode加密(过DeFender)

最近更新频率明显下降我懒&#xff0c;那么今天就来记录一下我们的一些常用的API的整理以及ShellCode的加密。 1.WinAPI整理 问我为什么要整理&#xff1f; 就是用起来的时候要左翻右翻 &#xff1a;&#xff1a; 烦死了 1.VirtualAlloc VirtualAlloc(NULL,sizeof(buf),MEM_…...

Stable Diffusion 使用详解(3)---- ControlNet

背景 炼丹师在AI绘画的过程中&#xff0c;由于Stable Diffusion的原理是水滴式的扩散作图原理&#xff0c;其实在前面也有提到&#xff0c;他的发挥是‘不稳定’的&#xff0c;因为你没有办法做到精确控制&#xff0c;只能说是大致符合你的预期。你不能总依赖抽卡固定随机数种…...

pythonGame-实现简单的贪食蛇游戏

通过python简单复现贪食蛇游戏。 使用到的库函数&#xff1a; import pygame import time import random 游戏源码&#xff1a; import pygame import time import randompygame.init()white (255, 255, 255) yellow (255, 255, 102) black (0, 0, 0) red (213, 50, 80…...

2024年软件系统与信息处理国际会议(ICSSIP 2024)即将召开!

2024年软件系统与信息处理国际会议&#xff08;ICSSIP 2024&#xff09;将于2024年10月25-27日在中国昆明举行。引领技术前沿&#xff0c;共谋创新未来。ICSSIP 2024将汇聚来自世界各地的专家学者&#xff0c;他们将在会上分享最新的研究成果、技术突破及实践经验。会议议题涵盖…...

使用vscode连接开发机进行python debug

什么是debug&#xff1f; 当你刚开始学习Python编程时&#xff0c;可能会遇到代码不按预期运行的情况。这时&#xff0c;你就需要用到“debug”了。简单来说&#xff0c;“debug”就是能再程序中设置中断点并支持一行一行地运行代码&#xff0c;观测程序中变量的变化&#xff…...

(家用)汽车充电桩项目总结分析

1. 项目选题背景 &#xff08;1&#xff09;社招&#xff1a;公司想做这个方向&#xff0c;先让学习测试一下&#xff0c;而且不做Web或者APP&#xff0c;以某一个模块或者某一个部分为主 &#xff08;2&#xff09;非社招&#xff1a;之前在学校做的一个学习的项目 2. 充电…...

JMeter接口测试:测试中奖概率!

介绍 Apache JMeter 是 Apache 组织基于 Java 开发的压力测试工具&#xff0c;用于对软件做压力测试。JMeter 最初被设计用于 Web 应用测试&#xff0c;但后来扩展到了其他测试领域&#xff0c;可用于测试静态和动态资源&#xff0c;如静态文件、Java 小服务程序、CGI 脚本、J…...

生成式人工智能之路,从马尔可夫链到生成对抗网络

人工智能&#xff08;Artificial intelligence&#xff0c;AI&#xff09;技术在过去几年中取得了显著进展&#xff0c;其中生成式AI&#xff08;Generative AI&#xff09;因其强大的内容生成能力而备受关注。生成式AI可以创建新的文本、图像、音频、视频、代码以及其他形式的…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...