链式结构二叉树(递归暴力美学)

在这里插入图片描述


在这里插入图片描述


文章目录

  • 1. 链式结构二叉树
    • 1.1 二叉树创建
  • 2. 前中后序遍历
    • 2.1 遍历规则
    • 2.2 代码实现
      • 图文理解
  • 3. 结点个数以及高度等
    • 二叉树结点个数
      • 正确做法:
  • 4. 层序遍历
  • 5. 判断是否完全二叉树

1. 链式结构二叉树

完成了顺序结构二叉树的代码实现,可以知道其底层结构是类似顺序表的结构;
因此,链式结构的二叉树类似于链表结构。

二叉树的结构一般由指数据域和左右指针域这三个域组成。

typedef char BTDataType;typedef struct BinaryTreeNode
{BTDataType data; //当前结点数据域struct BinaryTreeNode* left; //指向当前结点左孩⼦struct BinaryTreeNode* right; //指向当前结点右孩⼦
}BTNode;

1.1 二叉树创建

由于二叉树的代码实现过于复杂,因此这里采用手动创建一棵链式二叉树方便后续思路的代码实现。

单独封装一个函数可用来申请结点(和链表一样);
手动创建多个结点,并让其形成一棵二叉树。

BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail!");exit(1);}//malloc成功node->data = x;node->left = node->right = NULL;return node;
}
//手动构造一颗二叉树
BTNode* CreaterTree()
{BTNode* newnodeA = BuyNode('A');BTNode* newnodeB = BuyNode('B');BTNode* newnodeC = BuyNode('C');BTNode* newnodeD = BuyNode('D');BTNode* newnodeE = BuyNode('E');BTNode* newnodeF = BuyNode('F');newnodeA->left = newnodeB;newnodeA->right = newnodeC;newnodeB->left = newnodeD;newnodeC->left = newnodeE;newnodeC->right = newnodeF;return newnodeA;
}

在这里插入图片描述

2. 前中后序遍历

既然是二叉树,那必然也离不开遍历。因此,我们有多种遍历方式。

2.1 遍历规则

按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  1. 前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右子树之前
    访问顺序为:根结点、左子树、右子树(简称:根、左、右)
  2. 中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中(间)
    访问顺序为:左子树、根结点、右子树(简称:左、根、右)
  3. 后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后
    访问顺序为:左子树、右子树、根结点(简称:左、右、根)

以前序遍历为例如下图所示:
遵循前序遍历的规则:
1 先是访问A结点,然后进入左子树;
2. 在左子树中访问B根结点,进入B结点的左子树;
3. 在左子树中访问D根结点,而D中没有左子树和右子树,返回访问B的右子树;
4. B的右子树不存在,返回访问A的右子树;
5. 在右子树中访问C根结点,进入C结点的左子树;
6. 在左子树中访问E根结点,而E中没有左子树和右子树,返回访问C的右子树;
7. 在右子树中访问F根结点,F中没有左子树和右子树,遍历结束。

因此,前序遍历出来的数据是: A B D NULL NULL NULL C E NULL NULL F NULL NULL (NULL表示空)
在这里插入图片描述

图文理解

在这里插入图片描述

2.2 代码实现

为了方便理解,建议看完此二篇。
函数栈帧的创建和销毁.

函数递归的理解 <-- 详见此文


前序遍历
//前序遍历 --- 根左右
void PreOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%c ", root->data);PreOrder(root->left);PreOrder(root->right);
}

图文理解

以上文的二叉树,前序遍历为例:
在这里插入图片描述


中序遍历
//中序遍历 --- 左根右
void InOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%c ", root->data);InOrder(root->right);
}
后序遍历
//后序遍历 --- 左右根
void PostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%c ", root->data);
}

3. 结点个数以及高度等

二叉树结点个数

错误示例1:

int BinaryTreeSize(BTNode* root)
{static int size = 0;if (root == NULL){return 0;}++size;BinaryTreeSize(root->left);BinaryTreeSize(root->right);return size;
}

我们开始的想法是通过调用该函数,在里面通过变量size计数,但每次递推调用函数的时候size又会重新置为0,因此我们又考虑用static修饰size延长其生命周期,使得每次递推的时候都能使size保存上一个函数调用的值最后返回size的值得到该二叉树的结点个数。

但是,这明显存在一个错误,如果我们再次计算这个二叉树结点个数会出现什么情况?
在这里插入图片描述
我们打断点调试会发现size的值是从6开始的,这是为什么呢?
很明显,size被static修饰延长了生命周期,使得该变量不再是因为栈空间的结束而销毁。因此,该做法是不可取的。
在这里插入图片描述

错误示例2:

void BinaryTreeSize(BTNode* root, int* psize)
{if (root == NULL){return 0;}++(*psize);BinaryTreeSize(root->left,psize);BinaryTreeSize(root->right,psize);
}

既然我们不能从函数内部计数,那么我们是否能在函数外部定义指针变量size(要使得形参的改变能影响实参)来计数呢?
虽然解决了生命周期被延长的做法,但下次调用函数依旧会出现问题,还是因为size没有从0开始(需要手动置为0)。

正确做法:

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

深刻理解了递归和栈帧空间的创建销毁思想后,一棵二叉树是由根结点、左子树和右子树组成的,那么计算结点个数自然而然就是 1 + 左子树 + 右子树

4. 层序遍历

建议看完此篇。
栈和队列 <-- 详见此文

层序遍历:从所在二叉树的根结点出发,先访问第⼀层的树根结点,然后从左到右访问第2
层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程。

实现层序遍历需要额外借助数据结构:队列

  1. 将二叉树的根节点传给队列(队列可根据根节点找到左子树和右子树);
  2. 取队头元素并打印,同时删除队头元素;
  3. 若存在左孩子或右孩子,依次入队列;
  4. 继续取队头元素并打印,删除队头元素同时将队头的左孩子和右孩子入队列(存在情况下);
  5. 如此循环下去,直到队列为空完成了层序遍历。

在这里插入图片描述

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

5. 判断是否完全二叉树

非完全二叉树:
在这里插入图片描述
完全二叉树:
在这里插入图片描述

// 判断⼆叉树是否是完全⼆叉树
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);if (top == NULL){break;}//把不为空的队头节点的左右孩子入队列QueuePush(&q, top->left);QueuePush(&q, top->right);}//队列不一定为空,继续取队头出队头while (!QueueEmpty(&q)){BTNode* top = QueueFront(&q);QueuePop(&q);if (top != NULL){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}

在这里插入图片描述


在这里插入图片描述


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

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

相关文章

JS:将JS对象格式化为php语法形式(完美支持无unicode编码匹配的正则)

/*** 格式化Object数据为php语法形式* param {*} obj 任意数据* param {String} spaceLen 缩略符长度&#xff1a;必须在2~65536之间&#xff0c;否则默认为2* return {String} 格式化后的PHP语法字符串*/ function formatToPhp(obj, spaceLen) {formatToPhp function (obj, s…

Kubernetes 中 BGP 与二层网络的较量:究竟孰轻孰重?

如果你曾搭建过Kubernetes集群,就会知道网络配置是一个很容易让人深陷其中的领域。在负载均衡器、服务通告和IP管理之间,你要同时应对许多变动的因素。对于许多配置而言,使用二层(L2)网络就完全能满足需求。但边界网关协议(BGP)—— 支撑互联网运行的技术 —— 也逐渐出…

Linux提权--John碰撞密码提权

​John the Ripper​&#xff08;简称 John&#xff09;是一个常用的密码破解工具&#xff0c;可以通过暴力破解、字典攻击、规则攻击等方式&#xff0c;尝试猜解用户密码。密码的弱度是提权攻击中的一个重要因素&#xff0c;如果某个用户的密码非常简单或是默认密码&#xff0…

大数据学习之Spark分布式计算框架RDD、内核进阶

一.RDD 28.RDD_为什么需要RDD 29.RDD_定义 30.RDD_五大特性总述 31.RDD_五大特性1 32.RDD_五大特性2 33.RDD_五大特性3 34.RDD_五大特性4 35.RDD_五大特性5 36.RDD_五大特性总结 37.RDD_创建概述 38.RDD_并行化创建 演示代码&#xff1a; // 获取当前 RDD 的分区数 Since ( …

[创业之路-286]:《产品开发管理-方法.流程.工具 》-1- IPD两个跨职能团队的组织

IPD&#xff08;集成产品开发&#xff09;中的两个重要跨职能组织是IPMT&#xff08;集成产品管理团队&#xff09;和PDT&#xff08;产品开发团队&#xff09;。 在IPD&#xff08;集成产品开发&#xff09;体系中&#xff0c;IRB&#xff08;投资评审委员会&#xff09;、IPM…

maven详细讲解

学习目标 那什么是mavenmaven概念以及核心思想maven构建的生命周期、阶段以及目标maven仓库有哪些&#xff1f;maven依赖 那什么是maven&#xff1f;maven概念以及核心思想&#xff0c;maven构建的生命周期、阶段以及目标&#xff1f; 那什么是maven Maven是一个项目管理和构建…

DeepSeek 提示词之角色扮演的使用技巧

老六哥的小提示&#xff1a;我们可能不会被AI轻易淘汰&#xff0c;但是会被“会使用AI的人”淘汰。 在DeepSeek的官方提示库中&#xff0c;有“角色扮演&#xff08;自定义人设&#xff09;”的提示词案例。截图如下&#xff1a; 在“角色扮演”的提示词案例中&#xff0c;其实…

第二个Qt开发实例:在Qt中利用GPIO子系统和sysfs伪文件系统实现按钮(Push Button)点击控制GPIO口(效果为LED2灯的灭和亮)

引言 本文承接博文 https://blog.csdn.net/wenhao_ir/article/details/145420998 里的代码&#xff0c;在那里面代码的基础上添加上利用sysfs伪文件系统实现按钮(Push Button)点击控制GPIO口的代码&#xff0c;进而实现LED2灯的灭和亮。 最终的效果是点击下面的LED按钮实现LED…

登山第十七梯:矩形拟合——无惧噪声

文章目录 一 摘要 二 资源 三 内容 (文章末尾提供源代码) 一 摘要 目前,获取点集的矩形拟合结果的主要方法是计算其最小外包直立矩形或者旋转矩形。这些方法简单、易用,在数据质量良好的情况下能够较好的贴合矩形形状。然而,在数据缺失时,最小外包围盒方法将会…

57. Uboot图形化界面配置

一、Uboot图形化配置方法 1、通过终端配置。 2、进入到uboot的源码根目录下。 3、首先默认配置 make mx6ull_alientek_emmc_defconfig //默认配置 4、输入make menuconfig。打开图形化配置界面。 5、注意&#xff0c;新电脑需要安装ncurses库。sudo apt-get install libncurs…

Java面试场景题分享

假设你在做电商秒杀活动&#xff0c;秒杀开始时&#xff0c;成千上万的用户同时请求抢购商品。你会如何设计系统来处理这些请求&#xff0c;确保库存不超卖 你如何保证库存的准确性&#xff1f; 这个问题引导你思考如何在高并发下确保库存更新的原子性&#xff0c;最直接的方式…

kalman滤波器C++设计仿真实例第三篇

1. 仿真场景 水面上有条船在做匀速直线航行&#xff0c;航行过程中由于风和浪的影响&#xff0c;会有些随机的干扰&#xff0c;也就是会有些随机的加速度作用在船身上&#xff0c;这个随机加速度的均方差大约是0.1&#xff0c;也就是说方差是0.01。船上搭载GPS设备&#xff0c;…

(2025|ICLR,音频 LLM,蒸馏/ALLD,跨模态学习,语音质量评估,MOS)音频 LLM 可作为描述性语音质量评估器

Audio Large Language Models Can Be Descriptive Speech Quality Evaluators 目录 1. 概述 2. 研究背景与动机 3. 方法 3.1 语音质量评估数据集 3.2 ALLD 对齐策略 4. 实验结果分析 4.1 MOS 评分预测&#xff08;数值评估&#xff09; 4.2 迁移能力&#xff08;在不同…

stm32生成hex文件详解

1.产生的map文件干啥的&#xff1f; 2.组成情况&#xff1f;&#xff1f;&#xff1f; 废话少说&#xff0c;直接上代码具体内容况&#xff1a; Component: ARM Compiler 5.06 update 7 (build 960) Tool: armlink [4d3601]Section Cross Referencesstartup_stm32f103xe.o(S…

百度热力图数据获取,原理,处理及论文应用6

目录 0、数据简介0、示例数据1、百度热力图数据日期如何选择1.1、其他实验数据的时间1.2、看日历1.3、看天气 2、百度热力图几天够研究&#xff1f;部分文章统计3、数据原理3.1.1 ** 这个比较重要&#xff0c;后面还会再次出现。核密度的值怎么理解&#xff1f;**3.1.2 Csv->…

汽车自动驾驶AI

汽车自动驾驶AI是当前汽车技术领域的前沿方向&#xff0c;以下是关于汽车自动驾驶AI的详细介绍&#xff1a; 技术原理 感知系统&#xff1a;自动驾驶汽车通过多种传感器&#xff08;如激光雷达、摄像头、雷达、超声波传感器等&#xff09;收集周围环境的信息。AI算法对这些传感…

[转]Java面试近一个月的面试总结

本文是在学习中的总结&#xff0c;欢迎转载但请注明出处&#xff1a;http://blog.csdn.net/pistolove/article/details/46753275 前言 打算换个工作&#xff0c;近一个月面试了不少的公司&#xff0c;下面将一些面试经验和思考分享给大家。另外校招也快要开始了&#xff0c;为…

出租车特殊计费表算法解析与实现

目录 引言算法核心概念 特殊计费规则解析数据类型与输入输出算法数学原理 数字位判断与处理逻辑数值转换与累加计算算法框架图Python 实现 代码展示代码解析Python 实现的优势与局限C 语言实现 代码展示代码解析C 语言实现的性能特点性能分析与优化 性能分析 时间复杂度空间复杂…

学习threejs,tga格式图片文件贴图

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️TGA图片1.2 ☘️THREE.Mesh…

MSPFN 代码复现

1、环境配置 conda create -n MSPFN python3.9 conda activate MSPFN pip install opencv-python pip install tensorflow pip install tqdm pip install matplotlib2、train 2.1 创建数据集 2.1.1 数据集格式 |--rainysamples |--file1&#xff1a; |--file2:|--fi…