做移动网站优化快速/一键关键词优化
前言:前面我们学习了堆的模拟实现,今天我们来进一步学习二叉树,当然了内容肯定是越来越难的,各位我们一起努力!
💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:数据结构 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
什么是树
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。光看文字可能大家理解不了,我们看下图。
树的相关概念
- 节点的度:一个节点含有的子树的个数称为该节点的度。 如上图:A的为3。
- 叶节点或终端节点:度为0的节点称为叶节点; 如上图:F、G、H、I…等节点为叶节点。
- 非终端节点或分支节点:度不为0的节点; 如上图:B、C、D…等节点为分支节点.
- 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点。 如上图:A是B的父节点。
- 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点。 如上图:B是A的孩子节点。
- 兄弟节点:具有相同父节点的节点互称为兄弟节点。 如上图:B、C是兄弟节点。
- 树的度:一棵树中,最大的节点的度称为树的度。 如上图:树的度为5。
- 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推。
- 树的高度或深度:树中节点的最大层次。如上图:树的高度为4。
- 堂兄弟节点:双亲在同一层的节点互为堂兄弟。如上图:G、G互为兄弟节点 。
- 节点的祖先:从根到该节点所经分支上的所有节点。如上图:A是所有节点的祖先。
- 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙。
- 森林:由m(m>0)棵互不相交的树的集合称为森林。
什么是二叉树
二叉树是一种常见的树型数据结构,由若干个节点组成,每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树有以下特点(如图所示):
- 每个节点最多有两个子节点,且子节点的位置是固定的。
- 左子节点在父节点的左边,右子节点在父节点的右边。
- 二叉树的子树也是二叉树。
- 二叉树的每个节点都有一个值,可以是任意类型的数据。
讲完了二叉树的基本性质,我们开始模拟实现二叉树吧!
二叉树的基本功能
- 前序遍历–根、左、右 – 深度优先遍历
- 计算树节点。
- 中序遍历–左、根、右
- 计算叶子节点
- 树的高度
- 求第k层结点的个数
- 二叉树查找值为x的结点
- 通过前序遍历的数组构建二叉树。
- 销毁二叉树
- 层序遍历 – 广度优先遍历
- 判断二叉树是否是完全二叉树
二叉树的初始化(手搓二叉树)
思路导读:由于通过数组创建二叉树比较难,我们先放在博客的后面在去讲解,但是我们又需要二叉树怎么办,那就手搓一个。
代码演示:
typedef int BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;}TreeNode;TreeNode* BuyNode(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 = BuyNode(1);TreeNode* node2 = BuyNode(30);TreeNode* node3 = BuyNode(2);TreeNode* node4 = BuyNode(71);TreeNode* node5 = BuyNode(99);TreeNode* node6 = BuyNode(11);TreeNode* node7 = BuyNode(21);node1->left = node2;node1->right = node3;node2->left = node4;node2->right = node5;node3->right = node7;node3->left = node6;return node1;
}
创建好后的树的结构如下图所示
二叉树的前序遍历
思路导读:二叉树的前序遍历指先遍历二叉树的根,左子树,在遍历右子树。我们可以先画个图来模拟一下它遍历的顺序如下图:
既然图都画出来了,我们肯定思路都大致清晰了,那用什么方式去遍历呢?循环还是什么?今天我们要讲的方式是递归解决二叉树的遍历,这种是目前比较简单的方式。
代码实现:对于刚刚接触二叉树的友友们可能还不能理解这个递归的方式,没事可以看下图的递归展开图帮助你进一步理解
void PrevOrder(TreeNode* root)//前序遍历--根、左、右 -- 深度优先遍历
{if (root == NULL){return NULL;}printf("%d ", root->data);PrevOrder(root->left);PrevOrder(root->right);
}
运行结果:
二叉树的中序遍历
思路导读:二叉树的中序遍历指先遍历左子树,再遍历根,最后遍历右子树。这个就不为大家再画递归展开图了,看代码!
代码演示:
void InOrder(TreeNode* root)//中序遍历--左、根、右
{if (root == NULL){return NULL;}InOrder(root->left);printf("%d ", root->data);InOrder(root->right);
}
运行结果:
计算树节点
思路导读:我们要想计算树节点的个数,我们只需要将其左子树,右子树,还有根的值全部算出有多少即可,我们只需通过像前序遍历的思想来计算。如果不懂的话可以看下面的递归展开图(博主就画了前几步)。
代码实现:
int TreeSize(TreeNode* root)//计算树节点
{if (root == NULL){return 0;}return TreeSize(root->right) + TreeSize(root->left) + 1;}
计算叶子节点
思路导读:我们可以通过遍历该树的左子树和右子树,如果左子树和右子树同时为NULL我们就让它返回1,以此类推,我们可以通过像前面一样的方式遍历二叉树达到计算叶子节点的效果(部分递归展开图)。
代码实现:
int TreeLeafSize(TreeNode* root)//计算叶子节点
{if (root == NULL){return 0;}if((root->left)== NULL &&(root->right) == NULL){return 1;}return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
计算树的高度
思路导读:计算树的高度我们可以通过比较它的左子树和右子树找出其树高度中较大的那个然后加上一即可算出来这个树的高度,怎么比较呢?那我们就可以通过利用fmax这个函数来比较其找到最大值。
(部分递归展开图如下)
代码实现:
int TreeHight(TreeNode* root)//树给高度
{if (root == NULL){return 0;}//fmax函数,它是C语言(C99)中的一个内置函数,用于比较两个浮点数的大小并返回较大值。return fmax(TreeHight(root->left), TreeHight(root->right)) + 1;
}
求第k层节点的个数
思路导读:要想求第k层节点的个数我们需要将该层中左子树和右子树的位置分别记录下来,然后将其相加就是该层的个数。那么另一个问题来了,我们如何找到是这一层呢?我们可以通过每让它往下走一层时,就让k-1,依次递归,当k完全等于1的时候说明已经到了这一层,再返回1即可。(递归展开图如下)
代码实现:
int TreeLevelK(TreeNode* root, int k)//求第k层结点的个数
{assert(k > 0);if (root == NULL)return 0;if (k == 1)return 1;
二叉树查找值为x的节点
思路导读:我们通过前面写了这么多的二叉树的接口,这里我们可以想到,我们先查左子树中是否有相同的,然后我们再去查看右子树中是否有相同的,如果左子树找到了就将该值返回即可。(部分递归展开图如下)
代码实现:
TreeNode* TreeFind(TreeNode* root, BTDataType x)//二叉树查找值为x的结点
{if (root == NULL){return NULL;}if (root->data == x){return root;} TreeNode* cur = TreeFind(root->left,x);//先找左子树,通过指针记录,防止找到了接着往下走if (cur){return cur;}TreeNode* cur1 = TreeFind(root->right, x);//再找右子树,同理指针记录if (cur1){return cur1;}return NULL;
}
通过前序遍历的数组构建二叉树
我们先假定传来的数组为:char arr[] = { 'A','B','D','#','#','E','#','H','#','#','C','F','#','#','G','#','#' };
该’#'代表NULL,因此我们先画出其前序遍历的展开图(如下):
然后我们只需要像前序遍历一样,将其按照根、左子树、右子树一样依次开辟结点赋值,此时我们要注意的是一定要使用指针,防止在递归的过程中其值不会变化。
代码实现如下:
TreeNode* TreeCreate2(char* a, int* pi)//通过前序遍历的数组构建二叉树
{if (*(a + *pi) =='#'){(*pi)++;return NULL ;}TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));root->data = *(a + (*pi)++);root->left = TreeCreate2(a, pi);root->right = TreeCreate2(a, pi);return root;
}
运行结果:
二叉树的销毁
思路导读:二叉树的销毁可以像二叉树的后序遍历一样先左子树、右子树
代码实现:
void DestoryTree(TreeNode* root)//销毁
{if (root == NULL){return NULL;}DestoryTree(root->left);DestoryTree(root->right);free(root);}
层序遍历 – 广度优先遍历
思路导读:我们知道二叉树的一个特性,每一个节点都有俩个子节点,因此我们在可以充分的利用这个特性来实现我们层序遍历,我们可以模拟实现一个队列,让二叉树的根先存进去队列,然后打印其数据,就打印了第一层的数据,此时我们要打印第二层的数据,我们只需要将根的左子树和右子树在分别存入队列,在第二次循环中在依次打印即可实现层序遍历了。记住一定在队列中存的是二叉树根的地址而不是值(如下图所示)
代码实现:
void levelorder(TreeNode* root)//层序遍历 -- 广度优先遍历
{QNode q1;QueueInit(&q1);// TreeHight(root);if (root){//QueuePush(Queue * pq, QDataType x)QueuePush(&q1, root);}int level = 1;while (!QueueEmpty(&q1)){while (level--){TreeNode* front = QueueFront(&q1);//将头元素地址保存在二叉树中QueuePop(&q1);printf("%c ", front->data);if (front->left){QueuePush(&q1, front->left);}if (front->right){QueuePush(&q1, front->right);}}level = QueueSize(&q1);printf("\n");}QueueDestroy(&q1);
测试函数:
void Test1()
{TreeNode* root = CreateTree1();char arr[] = { 'A','B','D','#','#','E','#','H','#','#','C','F','#','#','G','#','#' };int i = 0;levelorder(TreeCreate2(arr, &i));
}
运行结果:
判断是否是完全二叉树
思路导读:我们可以像前面一样,让它们依次层次入队列,如果在入队列的过程中就碰到了NULL,就说明其不是完全二叉树,然后再将最后一层中队列的元素依次出队列,如果出队列的途中也碰到了NULL也就说明其不是完全二叉树。如果都没碰到则是完全二叉树。
代码实现:
bool TreeComplete(TreeNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);QueuePop(&q);if (front == NULL)break;QueuePush(&q, front->left);QueuePush(&q, front->right);}// 前面遇到空以后,后面还有非空就不是完全二叉树while (!QueueEmpty(&q)){TreeNode* front = QueueFront(&q);QueuePop(&q);if (front){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}
结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。
相关文章:

【数据结构】二叉树的模拟实现
前言:前面我们学习了堆的模拟实现,今天我们来进一步学习二叉树,当然了内容肯定是越来越难的,各位我们一起努力! 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:数据结构 👈 &…...

open3d bug:pcd转txt前后位姿发生改变
1、open3d bug:pcd转txt前后位姿发生改变 open3d会对原有结果进行一个微小位姿变换 import open3d as o3d import numpy as np# 读取PCD点云文件 pcd o3d.io.read_point_cloud(/newdisk/darren_pty/zoom_centered_s2.pcd)# 获取点云坐标 points pcd.points# 指定…...

持续集成交付CICD:Jenkins使用GitLab共享库实现基于Ansible的CD流水线部署前后端应用
目录 一、实验 1.部署Ansible自动化运维工具 2.K8S 节点安装nginx 3.Jenkins使用GitLab共享库实现基于Ansible的CD流水线部署前后端应用 二、问题 1.ansible安装报错 2.ansible远程ping失败 3. Jenkins流水线通过ansible命令直接ping多台机器的网络状态报错 一、实验 …...

OpenAI 疑似正在进行 GPT-4.5 灰度测试!
大家好,我是二狗。 今天,有网友爆料OpenAI疑似正在进行GPT-4.5灰度测试! 当网友询问ChatGPT API调用查询模型的确切名称是什么时? ChatGPT的回答竟然是 gpt-4.5-turbo。 也有网友测试之后发现仍然是GPT-4模型。 这是有网友指…...

DC-6靶场
DC-6靶场下载: https://www.five86.com/downloads/DC-6.zip 下载后解压会有一个DC-3.ova文件,直接在vm虚拟机点击左上角打开-->文件-->选中这个.ova文件就能创建靶场,kali和靶机都调整至NAT模式,即可开始渗透 首先进行主…...

单片机应用实例:LED显示电脑电子钟
本例介绍一种用LED制作的电脑电子钟(电脑万年历)。其制作完成装潢后的照片如下图: 上图中,年、月、日及时间选用的是1.2寸共阳数码管,星期选用的是2.3寸数码管,温度选用的是0.5寸数码管,也可根据…...

会议剪影 | 思腾合力受邀出席首届CCF数字医学学术年会
首届CCF数字医学学术年会(CCF Digital Medicine Symposium,DMS)于2023年12月15日-17日在苏州CCF业务总部召开。这次会议的成功召开,标志着数字医学领域进入了一个新的时代,计算机技术和人工智能在医学领域的应用和发展…...

node.js mongoose中间件(middleware)
目录 简介 定义模型 注册中间件 创建doc实例,并进行增删改查 方法名和注册的中间件名相匹配 执行结果 分析 错误处理中间件 手动抛出错误 注意点 简介 在mongoose中,中间件是一种允许在执行数据库操作前(pre)或后&…...

[Toolschain cpp ros cmakelist python vscode] 记录写每次项目重复的设置和配置 不断更新
写在前面 用以前的设置,快速配置项目,以防长久不用忘记,部分资料在资源文件里还没有整理 outline cmakelist 复用vscode 找到头文件vscode debug现有代码直接关联远端gitros杂记repo 杂记glog杂记 cmakelist 复用 包含了根据系统路径找库…...

【每日OJ—有效的括号(栈)】
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 1、有效的括号题目: 1.1方法讲解: 1.2代码实现: 总结 前言 世上有两种耀眼的光芒,一种是正在升起的太阳&#…...

.gitignore和git lfs学习
The ninth day——12.18 1. .gitignore 忽略规则优先级 从命令行中读取可用的忽略规则当前目录定义的规则父级目录定义的规则,依次递推$GIT_DIR/info/exclude 文件中定义的规则core.excludesfile中定义的全局规则 忽略规则匹配语法 空格不匹配任意文件ÿ…...

2023-12-18 C语言实现一个最简陋的B-Tree
点击 <C 语言编程核心突破> 快速C语言入门 C语言实现一个最简陋的B-Tree 前言要解决问题:想到的思路:其它的补充: 一、C语言B-Tree基本架构: 二、可视化总结 前言 要解决问题: 实现一个最简陋的B-Tree, 研究B-Tree的性质. 对于B树, 我是心向往之, 因为他是数据库的基…...

vite与webpack?
vite对比react-areate-app 1、构建速度 2、打包速度 3、打包文件体积...

距离矩阵路径优化Python Dijkstra(迪杰斯特拉)算法和冲突驱动子句学习
Dijkstra算法 Dijkstra 算法是一种流行的寻路算法,通常用于基于图的问题,例如在地图上查找两个城市之间的最短路径、确定送货卡车可能采取的最短路径,甚至创建游戏地图。其背后的直觉基于以下原则:从起始顶点访问所有相邻顶点&am…...

Selenium安装WebDriver:ChromeDriver与谷歌浏览器版本快速匹配_最新版120
最近在使用通过selenium操作Chrome浏览器时,安装中遇到了Chrome版本与浏览器驱动不匹配的的问题,在此记录安装下过程,如何快速找到与谷歌浏览器相匹配的ChromeDriver驱动版本。 1. 确定Chrome版本 我们首先确定自己的Chrome版本 Chrome设置…...

系统架构设计师教程(七)系统架构设计基础知识
系统架构设计基础知识 7.1 软件架构概念7.1.1 软件架构的定义7.1.2 软件架构设计与生命周期需求分析阶段设计阶段实现阶段构件组装阶段部署阶段后开发阶段 7.1.3 软件架构的重要性 7.2 基于架构的软件开发方法7.2.1 体系结构的设计方法概述7.2.2 概念与术语7.2.3 基于体系结构的…...

Bifrost 中间件 X-Requested-With 系统身份认证绕过漏洞复现
0x01 产品简介 Bifrost是一款面向生产环境的 MySQL,MariaDB,kafka 同步到Redis,MongoDB,ClickHouse等服务的异构中间件 0x02 漏洞概述 Bifrost 中间件 X-Requested-With 存在身份认证绕过漏洞,未经身份认证的攻击者可未授权创建管理员权限账号,可通过删除请求头实现身…...

OpenSSL 3.2.0新增Argon2支持——防GPU暴力攻击
1. 引言 OpenSSL新发布的3.20版本中,引入了一些新特性,包括: post-quantum方法Brainpool曲线QUICArgon2:Argon2 是一种慢哈希函数,在 2015 年获得 Password Hashing Competition 冠军,利用大量内存计算抵…...

数据结构--稀疏矩阵及Java实现
一、稀疏 sparsearray 数组 1、先看一个实际的需求 编写的五子棋程序中,有存盘退出和续上盘的功能。 分析问题: 因为该二维数组的很多值是默认值 0, 因此记录了很多没有意义的数据.->稀疏数组。 2、稀疏数组基本介绍 当一个数组中大部分元素为0…...

关于GPU使用过程中的若干问题
1.CUDA异常 问题描述:运行torch.cuda.is_available() 报错:cuda unknown error - this may be due to an incorrectly set up environment解决方案:重启 2.nvidia驱动版本不匹配 问题描述:运行nvidis-smi 报错:Fa…...

spring之面向切面:AOP(2)
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…...

【开题报告】基于uniapp的家庭记账小程序的设计与实现
1.研究背景 随着社会经济的发展和人们生活水平的提高,家庭财务管理变得越来越重要。家庭记账是一种重要的财务管理方式,通过记录和分析家庭的收入和支出情况,可以帮助家庭成员更好地理解和掌握自己的财务状况,合理规划和管理家庭…...

HTML5面试题
HTML5面试题 什么是HTML5?它与HTML4有何不同之处? HTML5是HTML的第五个主要版本,它引入了许多新的语义化元素、API和功能,以改进网页的结构、样式、交互和多媒体体验。 HTML5与HTML4的不同之处包括: 引入了一系列新的语…...

树莓派通过网线连接电脑并且设置设置链接wifi
好久没玩过树莓派了,系统进不去了,需要记录一下,之前总觉得自己会了,但是还是需要不断的翻阅资料。 树莓派 配置SD卡开启ssh - 哔哩哔哩 树莓派通过网线连接ssh 直接在sd卡建立一个ssh的文件,不要带任何后戳 ip查…...

C#拼接JSON
一、业务背景 最近项目需要与U8c对接,实现增删改查,借此机会,梳理一下C#解析Json字符串的问题。 这篇文章,先以新增接口为例。 二、新增接口 查看需要传入的json格式。 拼接json,无非就是{}和[]的来回嵌套。 首先&am…...

评价机器学习模型的指标
为了衡量一个机器学习模型的好坏,需要给定一个测试集,用模型对测试集中的每一个样本进行预测,并根据预测结果计算评价分数。 对于分类问题,常见的评价标准有准确率、精确率、召回率和F值等。给定测试集 𝒯 {(…...

C# WPF上位机开发(日志调试)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 程序开发的过程中,调试肯定是少不了的。比如说,这个时候,我们可以设置断点、查看变量、检查函数调用堆栈等等。…...

AR室内导航如何实现?技术与原理分析
随着科技的进步,我们生活中许多方面正在被重新定义。其中之一就是导航,尤其是室内导航。增强现实(AR)技术的出现为室内导航带来了革命性的变革。本文将深入探讨AR室内导航的技术与原理,以及它如何改变我们的生活方式。…...

计算机网络:物理层(奈氏准则和香农定理,含例题)
带你速通计算机网络期末 文章目录 一、码元和带宽 1、什么是码元 2、数字通信系统数据传输速率的两种表示方法 2.1、码元传输速率 2.2、信息传输速率 3、例题 3.1、例题1 3.2、例题2 4、带宽 二、奈氏准则(奈奎斯特定理) 1、奈氏准则简介 2、…...

天津仁爱学院专升本化学工程与工艺专业 《无机化学》考试大纲
天津仁爱学院化学工程与工艺专业高职升本入学考试《无机化学》课程考试大纲 一.参考教材 杨宏孝《无机化学简明教程》以及《无机化学简明教程学习指南》,高等教育出版社,2011年版。 二.考试基本要求 本考试要求将《无机化学》…...