【数据结构】二叉树的实现

目录

  • 1. 前言
  • 2. 二叉树的实现
    • 2.1 创建一棵树
    • 2.2 前序遍历
      • 2.2.1 分析
      • 2.2.2 代码实现
      • 2.2.3 递归展开图
    • 2.3 中序遍历
      • 2.3.1 分析
      • 2.3.2 代码实现
      • 2.3.3 递归展开图
    • 2.4 后序遍历
      • 2.4.1 分析
      • 2.4.2 代码实现
      • 2.4.3 递归展开图
    • 2.5 求节点个数
      • 2.5.1 分析
      • 2.5.2 代码实现
    • 2.6 求叶子节点个数
      • 2.6.1 分析
      • 2.6.2 代码实现
    • 2.7 求树高度
      • 2.7.1 分析
      • 2.7.2 代码实现
    • 2.8 求第K层节点的个数
      • 2.8.1 分析
      • 2.8.2 代码实现

1. 前言

在前面的博客中写了有关二叉树的介绍,那这次来写关于用C语言来实现与二叉树有关的一些操作。
与之前链表和顺序表不同的是,这里不实现增删查改。

2. 二叉树的实现

2.1 创建一棵树

直接手动创建一棵树,也就是直接malloc所有的节点。
在这里插入图片描述
直接创建6个节点,然后让node1的数据直接是1,让node2的数据直接是2,依次下去。
然后直接让node1的left = node2,它的right = node4;就按照上面的图来构建。
代码如下:

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;
}TreeNode;TreeNode* CreateTree()
{TreeNode* node1 = (TreeNode*)malloc(sizeof(TreeNode));assert(node1);TreeNode* node2 = (TreeNode*)malloc(sizeof(TreeNode));assert(node2);TreeNode* node3 = (TreeNode*)malloc(sizeof(TreeNode));assert(node3);TreeNode* node4 = (TreeNode*)malloc(sizeof(TreeNode));assert(node4);TreeNode* node5 = (TreeNode*)malloc(sizeof(TreeNode));assert(node5);TreeNode* node6 = (TreeNode*)malloc(sizeof(TreeNode));assert(node6);node1->data = 1;node2->data = 2;node3->data = 3;node4->data = 4;node5->data = 5;node6->data = 6;node1->left = node2;node1->right = node4;node2->left = node3;node2->right = NULL;node3->left = NULL;node3->right = NULL;node4->left = node5;node4->right = node6;node5->left = NULL;node5->right = NULL;node6->left = NULL;node6->right = NULL;
}

但是这个代码局限性太大,已经是写固定了的代码,不好再修改,下面这种会好一些。
不用管空。
想要其它形状的可以修改代码,做一定的增加或者就行。
代码如下:

TreeNode* BuyTreeNode(int x)
{TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode));assert(node);node->data = x;node->left = NULL;node->right = NULL;return node;
}TreeNode* CreateTree()
{TreeNode* node1 = BuyTreeNode(1);TreeNode* node2 = BuyTreeNode(2);TreeNode* node3 = BuyTreeNode(3);TreeNode* node4 = BuyTreeNode(4);TreeNode* node5 = BuyTreeNode(5);TreeNode* node6 = BuyTreeNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}

2.2 前序遍历

2.2.1 分析

前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
在这里插入图片描述
就实现这颗树的前序遍历。
先根,然后左子树,再右子树,初学时把NULL也带上,方便理解。
也就是下面这样。
在这里插入图片描述
先访问根,然后找左子树,左子树又得拆成根和左子树,一直到空。使用递归来实现。

2.2.2 代码实现

void PrevOrder(TreeNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}

结果和分析的一样:
在这里插入图片描述

2.2.3 递归展开图

在这里插入图片描述

2.3 中序遍历

2.3.1 分析

中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
同样以上面那棵树为例子。
先左子树,再根,再右子树。
在这里插入图片描述
这里遇到根先不是NULL,先走它的左子树,是空就打印返回。

2.3.2 代码实现

void InOrder(TreeNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}

结果与分析的是一样的:
在这里插入图片描述

2.3.3 递归展开图

在这里插入图片描述

2.4 后序遍历

2.4.1 分析

.后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
同样是以上面那棵树为例子,它的后序遍历就是:
在这里插入图片描述
先访问它的左子树,然后右子树,最后才是根。
要当左右都为空时才访问第一个节点。

2.4.2 代码实现

void PostOrder(TreeNode* root)
{if (root == NULL){printf("N ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->data);
}

在这里插入图片描述

递归展开方式也是一样的

2.4.3 递归展开图

在这里插入图片描述

2.5 求节点个数

2.5.1 分析

只要节点不为空,就加加,然后再调用左子树,右子树。
用全局的size,每次调用前先置空一些。
局部的使用不了,因为不能置空,再调用一次就会再上次的基础上累计。
在这里插入图片描述
同样是这课树节点数为6。

2.5.2 代码实现

int size = 0;
void TreeSize(TreeNode* root)
{if (root == NULL)return;++size;TreeSize(root->left);TreeSize(root->right);
}int main()
{  TreeNode* root = CreateTree();size = 0;TreeSize(root);printf("TreeSize:%d\n", size);return 0;
}

在这里插入图片描述
还有另一种实现:把树拆成左子树加右子树加1.
代码如下:

int TreeSize(TreeNode* root)
{return root == NULL ? 0 :TreeSize(root->left) +TreeSize(root->right) + 1;
}

结果还是一样的。
在这里插入图片描述
采用的就是分治法

2.6 求叶子节点个数

2.6.1 分析

先得判断一下树是不是空树,不是才能就行进行。
不是空树,而且左右节点都为空,就是叶子节点,就返回1;
不是空,也不是叶子节点就采用分治,树的节点就等于左右叶子节点的和。
在这里插入图片描述
在这里插入图片描述
同样是这棵树,叶子节点就是3.

2.6.2 代码实现


int TreeLeafSize(TreeNode* root)
{// 空 返回0if (root == NULL)return 0;// 不是空,是叶子 返回1if (root->left == NULL&& root->right == NULL)return 1;// 不是空 也不是叶子  分治=左右子树叶子之和return TreeLeafSize(root->left) +TreeLeafSize(root->right);
}
int main()
{TreeNode* root = CreateTree();printf("TreeLeafSize:%d\n", TreeLeafSize(root))return 0;
}

和分析的一样叶子节点个数就是3.
在这里插入图片描述

2.7 求树高度

2.7.1 分析

先要判断一下树是不是空树,是就为0。
不是空树,就要判断一下左子树和右子树那个更高,然后高的那个就加1。
在这里插入图片描述
同样以这棵树计算,这棵树的高度就是3

2.7.2 代码实现

int TreeHeight(TreeNode* root)
{if (root == NULL)return 0;int leftHeight = TreeHeight(root->left);int rightHeight = TreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}int main()
{TreeNode* root = CreateTree();printf("TreeHeight:%d\n", TreeHeight(root));return 0;
}

在这里插入图片描述


int TreeHeight(TreeNode* root)
{if (root == NULL)return 0;return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}

这里使用fmax返回大的数,需要包一个头文件<math.h>
结果也是一样的。

2.8 求第K层节点的个数

2.8.1 分析

同样采用分治。
如果是空树就返回0;
如果不为空,k=1,第一层就返回1;
如果不为空,且k>1,就返回左子树的k-1层加上右子树的k-1层。

在这里插入图片描述

同样以这棵树计算,k>1就说明再第一层的下面。这棵树的第三层的节点数就是,第二层的左加第二层的右;第二层的左又转化成第一层的左加第一层的右,为空就返回0。

2.8.2 代码实现

int TreeLevelK(TreeNode* root, int k)
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;return TreeLevelK(root->left, k - 1)+ TreeLevelK(root->right, k - 1);
}
int main()
{TreeNode* root = CreateTree();printf("TreeLevelK:%d\n", TreeLevelK(root, 3));return 0;
}

结果如下:
在这里插入图片描述
有问题请指出,大家一起进步!

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

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

相关文章

Linux 调试器 --- g d b 使用

目录 一&#xff1a;gdb简介 二&#xff1a;示例代码 三&#xff1a;使用 1.启动gdb 2.各种指令 <1>: 查看源代码 <2>:设置断点 <3>:查看断点信息 <4>:删除断点 <5>: run <6>:逐过程调试 <7>:逐语句调试 <8>:查…

TrustZone​之在安全状态之间切换

如果处理器处于NS.EL1,而软件想要转移到S.EL1,应该如何实现呢? 要改变安全状态,无论是向上还是向下,执行都必须经过EL3,如下图所示: 前面的图表显示了在不同安全状态之间移动涉及的步骤的示例序列。逐步进行解释: 进入较高的异常级别需要一个异常。通常,此异常…

相关基础知识

本文引注&#xff1a; https://zhuanlan.zhihu.com/p/447221519 1.方差 2.自协方差矩阵 3.自相关矩阵 4.互协方差矩阵 5.互相关矩阵 6.相关系数 7.自相关函数、自协方差函数与功率谱密度 8.互相关函数、互协方差函数与互功率谱密度

时间选择器

<el-form-item label"时间范围"><!-- <el-date-picker size"small"v-model"createTime"type"daterange"range-separator"至"start-placeholder"请输入起始创建时间"end-placeholder"请输入终止创…

无线网优AP、SW发现控制器

目录 无线网优解决的问题 1、信号覆盖不足的原因 2、信道繁忙 3、非802.11干扰 4、协商速率低 5、漫游效果差 6、有线带宽阻塞 无线网优方法 交换机发现与激活 一&#xff0c;交换机发现控制器方式 1、二层广播 2、DHCP option43方式 3、DNS域名解析方式 4、trou…

基于springboot + vue大学生竞赛管理系统

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

【AIGC】AI作图最全提示词prompt集合(收藏级)

目录 一、正向和负向提示词 二、作图参数 你好&#xff0c;我是giszz. AI做图真是太爽了&#xff0c;解放生产力&#xff0c;发展生产力。 但是&#xff0c;你是不是也总疑惑&#xff0c;为什么别人的图&#xff0c;表现力那么丰富呢&#xff0c;而且指哪打哪&#xff0c;要…

DFT(离散傅里叶变换)的通俗理解

本文包含了博主对离散傅里叶变换&#xff0c;负频率&#xff0c;实信号与复信号频谱的理解&#xff0c;如有不妥&#xff0c;欢迎各位批评指正与讨论。 文章目录 DFT的理解信号的频谱实信号的频谱复信号的频谱 DFT的理解 傅里叶变换是一种将信号从时域转换到频域的数学工具。…

通信标准化协会,信通院及量子信息网络产业联盟调研玻色量子,共绘实用化量子未来!

8月14日&#xff0c;中国通信标准化协会&#xff0c;信通院标准所及量子信息网络产业联盟等单位领导走访调研北京玻色量子科技有限公司&#xff08;以下简称“玻色量子”&#xff09;&#xff0c;参观了玻色量子公司及自建的十万颗粒洁净度的光量子信息技术实验室&#x1f517;…

STM32下载程序的五种方法

刚开始学习 STM32 的时候&#xff0c;很多小伙伴满怀热情买好了各种设备&#xff0c;但很快就遇到了第一个拦路虎——如何将写好的代码烧进去这个黑乎乎的芯片&#xff5e; STM32 的烧录方式多样且灵活&#xff0c;可以根据实际需求选择适合的方式来将程序烧录到芯片中。本文将…

10年前,我就用 SQL注入方式发现了学校网站的漏洞

大家好&#xff0c;我是风筝。 事情是这样子的&#xff0c;在10年以前&#xff0c;某个月黑风高夜的夜里&#xff0c;虽然这么说有点暴露年龄了&#xff0c;但无所谓&#xff0c;毕竟我也才18而已。我打开电脑&#xff0c;在浏览器中输入我们高中学校的网址&#xff0c;页面很…

TCP首部格式_基本知识

TCP首部格式 表格索引: 源端口目的端口 序号 确认号 数据偏移保留 ACK等 窗口检验和紧急指针 TCP报文段首部格式图 源端口与目的端口: 各占16位 序号:占32比特&#xff0c;取值范围0~232-1。当序号增加到最后一个时&#xff0c;下一个序号又回到0。用来指出本TCP报文段数据载…

ctfhub技能树_web_信息泄露

目录 二、信息泄露 2.1、目录遍历 2.2、Phpinfo 2.3、备份文件下载 2.3.1、网站源码 2.3.2、bak文件 2.3.3、vim缓存 2.3.4、.DS_Store 2.4、Git泄露 2.4.1、log 2.4.2、stash 2.4.3、index 2.5、SVN泄露 2.6、HG泄露 二、信息泄露 2.1、目录遍历 注&#xff1…

【ArcGIS Pro微课1000例】0050:如何清除坐标系信息

文章目录 一、目的二、方法1. 使用【定义投影】工具2. 清除数据的投影信息3. 删除坐标文件 一、目的 地理信息数据的坐标系是将地理信息数据进行融合、叠加、分析的重要数学框架&#xff0c;而其描述信息是非常重要的元数据&#xff0c;涉及整个国家的测绘坐标系统&#xff0c…

DSSS技术和OFDM技术

本内容为学习笔记&#xff0c;内容不一定正确&#xff0c;请多处参考进行理解 https://zhuanlan.zhihu.com/p/636853588 https://baike.baidu.com/item/OFDM/5790826?frge_ala https://zhuanlan.zhihu.com/p/515701960?utm_id0 一、 DSSS技术 信号替代&#xff1a;DSSS技术为…

C++ 操作MinIO做文件数据的上传和下载(踩坑与经验)包含编译包

前言 最近在做项目流程优化&#xff0c;准备将之前的java对文件的操作转换到c端&#xff0c;因此做了基于c的minio操作的测试demo。期间的各种踩坑与问题&#xff0c;花了一天时间总算是成功了&#xff0c;当然还有一些小问题&#xff0c;等待后续其他大拿解决。 项目环境 v…

Jmeter调用本地Exe程序

背景&#xff1a; 候使用C#编译的小工具制作压测的请求的入参&#xff0c;因Jmeter无法调用C#的方法&#xff0c;可以把C#编译个exe程序&#xff0c;在启动压测前&#xff0c;让JMeter调用本地的exe批量生成压测数据。 使用步骤&#xff1a; 打开Jmeter&#xff0c;右击选择…

【Vue】使用cmd命令创建vue项目

上一篇&#xff1a; node的安装与配置 https://blog.csdn.net/m0_67930426/article/details/134562278?spm1001.2014.3001.5502 目录 一.创建空文件夹专门存放vue项目 二. 查看node , npm 和vue脚手架的版本 三.安装vue脚手架 四.创建vue项目 五.运行项目 一.创建空文件…

第五期丨酷雷曼无人机技能培训圆满举办

第5期无人机技能提升培训 2023年11月28日-29日&#xff0c;为期2天的酷雷曼第五期无人机技能提升培训会圆满举办。本届培训会盛况依旧&#xff0c;数十位合作商不远千里相约&#xff0c;共同提升专业水准&#xff0c;考取执照证书。 入场签到 初冬已至&#xff0c;尽管天气渐…

properties出现中文乱码解决方法(万能)

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 在使用Properties类的时候,中文出现乱码 如图所示: 正常思维来讲,估计是中文编码有问题,于是我将其改为UTF-8的编码方式 通过下方的改动: 可到了这一步,中文还是乱码(这一步改成功的网友可自动立场,没改成功的网…