【数据结构】二叉树的实现
目录
- 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;
}
结果如下:

有问题请指出,大家一起进步!
相关文章:
【数据结构】二叉树的实现
目录 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 求叶子节点个数…...
振弦采集仪在土体与岩体监测中的可靠性与精度分析
振弦采集仪在土体与岩体监测中的可靠性与精度分析 振弦采集仪是一种用于土体和岩体监测的重要设备,它可以通过测量振动信号来获取土体或岩体的力学参数,如应力、应变、弹性模量等。而振弦采集仪的可靠性和精度是影响其应用效果的关键因素。 首先&#x…...
C语言进阶之路-指针、数组等混合小boss篇
目录 一、学习目标: 二、指针、数组的组合技能 引言 指针数组 语法 数组指针 三、勇士闯关秘籍 四、大杂脍 总结 一、学习目标: 知识点: 明确指针数组的用法和特点掌握数组指针的用法和特点回顾循环等小怪用法和特点 二、指针、数…...
【矩阵论】Chapter 7—Hermite矩阵与正定矩阵知识点总结复习
文章目录 1 Hermite矩阵2 Hermite二次型3 Hermite正定(非负定矩阵)4 矩阵不等式 1 Hermite矩阵 定义 设 A A A为 n n n阶方阵,如果称 A A A为Hermite矩阵,则需满足 A H A A^HA AHA,其中 A H A^H AH表示 A A A的共轭转…...
Golang语言基础之切片
概述 数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性 func arraySum(x [3]int) int{sum : 0for _, v : range x{sum sum v}return sum } 这个求和函数只能接受 [3]int 类型,其他的都不支持。 切片 切片(Slic…...
SpringCloud-服务消费者Fegin调用时无法获取异常信息
一、前言 假设有以下需求: 服务消费者A调用服务提供者B往MySQL新增一条人员信息服务提供者做了一个逻辑判断:若无该人员信息则新增,若已存在该人员信息,则返回给消费者异常状态码及异常信息:“请勿添加重复数据” 问…...
re:invent 2023 Amazon Q 初体验
授权声明:本篇文章授权活动官方亚马逊云科技文章转发、改写权,包括不限于在 Developer Centre,知乎,自媒体平台,第三方开发者媒体等亚马逊云科技官方渠道 前言 亚马逊云科技在2023 re:Invent全球大会上宣布推出 Amazon…...
认知觉醒(四)
认知觉醒(四) 第三节 耐心:得耐心者得天下 20世纪八九十年代,金庸的武侠小说风靡全国。如今,虽然几十年过去了,金庸先生也已与世长辞,但他留下的作品依然广受欢迎,被奉为经典。如此成就,自然…...
AI模型部署 | onnxruntime部署YOLOv8分割模型详细教程
本文首发于公众号【DeepDriving】,欢迎关注。 0. 引言 我之前写的文章《基于YOLOv8分割模型实现垃圾识别》介绍了如何使用YOLOv8分割模型来实现垃圾识别,主要是介绍如何用自定义的数据集来训练YOLOv8分割模型。那么训练好的模型该如何部署呢?…...
模拟电路学习笔记(一)之芯片篇(持续更新)
模拟电路学习笔记(一)之芯片篇(持续更新) 1.CD4047BE芯片 CD4047是一种包含高电压的多谐振荡器,该器件的操作可以在两种模式下完成,分别是单稳态和非稳态。CD4047需要一个外部电阻器和电容器来决定单稳态…...
如何利用CentOS7+docker+jenkins+gitee部署springboot+vue前后端项目(保姆教程)
博主介绍:Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 🍅文末获取源码下载地址🍅 👇🏻 精彩专栏推荐订阅👇🏻…...
qt 5.15.2 主窗体事件及绘制功能
qt 5.15.2 主窗体事件及绘制功能 显示主窗体效果图如下所示: main.cpp #include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);MainWindow w;w.setFixedWidth(600);w.setFixedHeight(6…...
(2)(2.4) TerraRanger Tower/Tower EVO(360度)
文章目录 前言 1 安装传感器并连接 2 通过地面站进行配置 3 参数说明 前言 TeraRanger Tower 可用于在 Loiter 和 AltHold 模式下进行目标规避。传感器的最大可用距离约为 4.5m。 TeraRanger Tower EVO 可用于在 Loiter 和 AltHold 模式下进行目标规避。传感器的最大可用…...
Redis_主从复制、哨兵模式、集群模式详解
Redis的主从复制 为什么Redis要引入主从复制?what? 在这里博主为小伙伴们简单的做下解释,可以了解一下 实际生产环境下,单机的redis服务器是无法满足实际的生产需求的。 第一,单机的redis服务器很容易发生单点故障&am…...
关于神舟-战神TA5NS系统重装问题
加装固态卡在log处无法开机问题 下面是我的步骤 1.按f7选择pe安装系统,然后发现卡在战神log处不转动 2.下载驱动 TA5NS驱动地址 下载RAID驱动(如果没有私信我,我网盘里有),拷到u盘中,然后进入pe系统里面…...
前端大文件上传webuploader(react + umi)
使用WebUploader还可以批量上传文件、支持缩略图等等众多参数选项可设置,以及多个事件方法可调用,你可以随心所欲的定制你要的上传组件。 分片上传 1.什么是分片上传 分片上传,就是将所要上传的文件,按照一定的大小,将…...
人大金仓(kingbase)数据库常用sql命令
一. 字段 1. 添加 alter table book add column book_id varchar not null, book_title varchar(10) default ;2. 删除 alter table book drop book_id, book_title;// 外键时 alter table book drop book_id, book_title cascade;3. 修改类型 alter table book alter colu…...
HashMap相关专题
前置知识:异或运算 异或运算介绍 异或有什么神奇之处(应用)? (1)快速比较两个值 (2)我们可以使用异或来使某些特定的位翻转,因为不管是0或者是1与1做异或将得到原值的相…...
threejs WebGLRenderer 像素比对画布大小的影响
官方文档 - WebGLRenderer .setPixelRatio ( value : number ) : undefined 设置设备像素比。通常用于避免HiDPI设备上绘图模糊 .setSize ( width : Integer, height : Integer, updateStyle : Boolean ) : undefined 将输出canvas的大小调整为(width, height)并考虑设备像素比…...
RocketMQTemplate.send() 与 RocketMQTemplate.syncSend() 方法详解
Apache RocketMQ 是一款强大的分布式消息中间件,与 Spring Boot 集成后,通过 RocketMQTemplate 提供了多种方法来发送消息。其中,send() 和 syncSend() 是两个常用的发送消息方法,本文将深入探讨它们的区别以及详细解释这两个方法…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
