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

在这里插入图片描述


在这里插入图片描述


文章目录

  • 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.rhkb.cn/news/13693.html

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

相关文章

复制粘贴小工具——Ditto

在日常工作中&#xff0c;复制粘贴是常见的操作&#xff0c;但Windows系统自带的剪贴板功能较为有限&#xff0c;只能保存最近一次的复制记录&#xff0c;这对于需要频繁复制粘贴的用户来说不太方便。今天&#xff0c;我们介绍一款开源、免费且功能强大的剪贴板增强工具——Dit…

【Unity3D小功能】Unity3D中实现超炫按钮悬停效果

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 先来看一下效果图&#xff1a; 感觉这种效果…

优化深度神经网络

训练集、开发集(验证集)、测试集 偏差与方差 正则化 L2正则 Dropout 随机丢弃部分神经元输入&#xff0c;经常用于计算机视觉的神经网络内&#xff0c;因为通常没有足够的训练数据&#xff0c;很容易出现过拟合的问题 数据增强 训练集规一化 可以使其图像更均匀&#xff0c;…

从java角度对比nodejs、fastapi,同步和异步区别

我之前一直用java语言编程&#xff0c;最近一年用python fastapi和nodejs nestjs开发了一些项目&#xff0c;站在java程序员的角度谈谈异步编程和同步编程的区别&#xff0c;主要在两方面 处理请求&#xff0c;java常用的tomcat是多线程处理请求并执行代码&#xff0c;同步阻塞…

《图解设计模式》笔记(五)一致性

十一、Composite模式&#xff1a;容器与内容的一致性 像文件夹与文件一样&#xff0c;文件夹中可以放子文件夹与文件&#xff0c;再比如容器中可以放更小的容器和具体内容。 Composite模式&#xff1a;使容器与内容具有一致性&#xff0c;创造出递归结构。 Composite&#x…

爬虫学习笔记之Robots协议相关整理

定义 Robots协议也称作爬虫协议、机器人协议&#xff0c;全名为网络爬虫排除标准&#xff0c;用来告诉爬虫和搜索引擎哪些页面可以爬取、哪些不可以。它通常是一个叫做robots.txt的文本文件&#xff0c;一般放在网站的根目录下。 robots.txt文件的样例 对有所爬虫均生效&#…

电脑可以自己换显卡吗?怎么操作

电脑是否可以自己换显卡主要取决于电脑的类型&#xff08;台式机或笔记本&#xff09;以及电脑的硬件配置。以下是对这一问题的详细解答及操作步骤&#xff1a; 一、判断电脑是否支持更换显卡 台式机&#xff1a;大多数台式电脑都支持更换显卡。只要主板上有PCIe插槽&#xff…

【玩转 Postman 接口测试与开发2_014】第11章:测试现成的 API 接口(下)——自动化接口测试脚本实战演练 + 测试集合共享

《API Testing and Development with Postman》最新第二版封面 文章目录 3 接口自动化测试实战3.1 测试环境的改造3.2 对列表查询接口的测试3.3 对查询单个实例的测试3.4 对新增接口的测试3.5 对修改接口的测试3.6 对删除接口的测试 4 测试集合的共享操作4.1 分享 Postman 集合…

华为支付-免密支付接入免密代扣说明

免密代扣包括支付并签约以及签约代扣场景。 开发者接入免密支付前需先申请开通签约代扣产品&#xff08;即申请配置免密代扣模板及协议模板ID&#xff09;。 华为支付以模板维度管理每一个代扣扣费服务&#xff0c;主要组成要素如下&#xff1a; 接入免密支付需注意&#x…

Redis - 全局ID生成器 RedisIdWorker

文章目录 Redis - 全局ID生成器 RedisIdWorker一、引言二、实现原理三、代码实现代码说明 四、使用示例示例说明 五、总结 Redis - 全局ID生成器 RedisIdWorker 一、引言 在分布式系统中&#xff0c;生成全局唯一ID是一个常见的需求。传统的自增ID生成方式在分布式环境下容易出…

YOLOv11实时目标检测 | 摄像头视频图片文件检测

在上篇文章中YOLO11环境部署 || 从检测到训练https://blog.csdn.net/2301_79442295/article/details/145414103#comments_36164492&#xff0c;我们详细探讨了YOLO11的部署以及推理训练&#xff0c;但是评论区的观众老爷就说了&#xff1a;“博主博主&#xff0c;你这个只能推理…

用Python获取股票数据并实现未来收盘价的预测

获取数据 先用下面这段代码获取上证指数的历史数据&#xff0c;得到的csv文件数据&#xff0c;为后面训练模型用的 import akshare as ak import pandas as pd# 获取上证指数历史数据 df ak.stock_zh_index_daily(symbol"sh000001")# 将数据保存到本地CSV文件 df.…

RK3576——USB3.2 OTG无法识别到USB设备

问题&#xff1a;使用硬盘接入到OTG接口无热插拔信息&#xff0c;接入DP显示屏无法正常识别到显示设备&#xff0c;但是能通过RKDdevTool工具烧录系统。 问题分析&#xff1a;由于热插拔功能实现是靠HUSB311芯片完成的&#xff0c;因此需要先确保HUSB311芯片驱动正常工作。 1. …

RabbitMQ深度探索:前置知识

消息中间件&#xff1a; 消息中间件基于队列模式实现异步 / 同步传输数据作用&#xff1a;可以实现支撑高并发、异步解耦、流量削峰、降低耦合 传统的 HTTP 请求存在的缺点&#xff1a; HTTP 请求基于响应的模型&#xff0c;在高并发的情况下&#xff0c;客户端发送大量的请求…

maven如何不把依赖的jar打包到同一个jar?

spring boot项目打jar包部署&#xff1a; 经过以下步骤&#xff0c; 最终会形成maven依赖的多个jar&#xff08;包括lib下添加的&#xff09;、 我们编写的程序代码打成一个jar&#xff0c;将程序jar与 依赖jar分开&#xff0c;便于管理&#xff1a; success&#xff1a; 最终…

网络工程师 (21)网络的性能

一、速率&#xff08;数据率或比特率&#xff09; 定义&#xff1a;数据在数字信道上传送的速率&#xff0c;通常以比特每秒&#xff08;bps&#xff09;为单位。常见的速率单位还有千比特每秒&#xff08;kbit/s&#xff09;、兆比特每秒&#xff08;Mbit/s&#xff09;和吉比…

UE5 蓝图学习计划 - Day 14:搭建基础游戏场景

在上一节中&#xff0c;我们 确定了游戏类型&#xff0c;并完成了 项目搭建、角色蓝图的基础设置&#xff08;移动&#xff09;。今天&#xff0c;我们将进一步完善 游戏场景&#xff0c;搭建 地形、墙壁、机关、触发器 等基础元素&#xff0c;并添加角色跳跃功能&#xff0c;为…

计算机毕业设计hadoop+spark+hive民宿推荐系统 酒店推荐系统 民宿价格预测 酒店价预测 机器学习 深度学习 Python爬虫 HDFS集群

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

金蝶云星空k3cloud webapi报“java.lang.Class cannot be cast to java.lang.String”的错误

最近在对接金蝶云星空k3cloud webapi时&#xff0c;报一个莫名其妙的转换异常&#xff0c;具体如下&#xff1a; 同步部门异常! ERP接口登录异常&#xff1a;java.lang.Class cannot be cast to java.lang.String at com.jkwms.k3cloudSyn.service.basics.DeptK3CloudService.…

html的字符实体和颜色表示

在HTML中&#xff0c;颜色可以通过以下几种方式表示&#xff0c;以下是具体的示例&#xff1a; 1. 十六进制颜色代码 十六进制颜色代码以#开头&#xff0c;后面跟随6个字符&#xff0c;每两个字符分别表示红色、绿色和蓝色的强度。例如&#xff1a; • #FF0000&#xff1a;纯红…