当前位置: 首页 > news >正文

【C语言】二叉树(BinaryTree)的创建、3种递归遍历、3种非递归遍历、结点度的实现

代码主要实现了以下功能:

  1. 二叉树相关数据结构定义
    定义了二叉树节点结构体 BiTNode,包含节点数据值(字符类型)以及指向左右子树的指针。
    定义了顺序栈结构体 SqStack,用于存储二叉树节点指针,实现非递归遍历。
  1. 二叉树的创建与遍历
    创建二叉树:通过 CreateBiTree 函数,根据输入的先序遍历字符序列(# 表示空节点),以递归方式创建二叉树。
    递归遍历:实现了二叉树的递归先序、中序、后序遍历函数,分别按照根 - 左 - 右、左 - 根 - 右、左 - 右 - 根的顺序输出节点字符序列。
    非递归遍历:借助栈实现了二叉树的非递归先序、中序、后序遍历函数,在遍历过程中除输出节点字符外,还输出节点进栈、出栈过程及栈顶节点字符。
  1. 二叉树相关应用实例
    统计节点度数:通过 TNodes 函数统计二叉树中度为 0、1、2 的节点个数。
    计算树的高度:利用 High 函数计算二叉树的高度。
    创建二叉排序树:通过 CreateBST 函数根据给定字符序列生成二叉排序树,并对创建的二叉树进行中序遍历及高度计算。
  1. 主函数功能整合
    在 main 函数中,依次调用上述函数完成以下操作:
    创建一棵二叉树并输出其递归和非递归的三种遍历结果及栈变化情况。
    统计该二叉树不同度数的节点个数。
    创建两棵二叉排序树并输出它们的中序遍历结果及高度。

祁许
为例

实现效果

祁许
祁许

完整代码

如下,注释详细

//
// Created by 13561 on 2024/11/28.
//#include<stdio.h>
#include<stdlib.h>
#include<string.h>#define ERROR   0
#define TRUE    1
#define OK      1
#define MAXSIZE 100typedef int Status;            //声明函数类型名
typedef  char TElemType;       //声明结点元素值的类型//定义二叉树结点类型
typedef  struct BiTNode {TElemType  		data;struct BiTNode  *lchild, *rchild;  	    //指向左右孩子结点的指针} BiTNode, *BiTree;// 栈
typedef struct {BiTree data[MAXSIZE];int top;
}SqStack;// 根据先序遍历的字符序列,创建一棵按二叉链表结构存储的二叉树,指针变量T指向二叉树的根节点
void CreateBiTree(BiTree *T) {TElemType ch;scanf(" %c",&ch);printf("Read character: %c\n", ch);// # 代表空结点if(ch == '#') {printf("#设置为空结点\n");*T = NULL;} else {*T = (BiTree)malloc(sizeof(BiTNode));if(!*T) {exit(0);}(*T)->data = ch;// 创建左、右子树CreateBiTree(&(*T)->lchild);CreateBiTree(&(*T)->rchild);}}// 递归先序遍历二叉树 T ,输出访问的结点字符序列
Status PreOrderTraverse(BiTree T) {// 根 - 左 - 右if(T) {printf("%c ",T->data);PreOrderTraverse(T->lchild);PreOrderTraverse(T->rchild);}return OK;
}// 递归中序遍历二叉树 T ,输出访问的结点字符序列
Status InOrderTraverse(BiTree T) {// 左 - 根 - 右if(T) {InOrderTraverse(T->lchild);printf("%c ",T->data);InOrderTraverse(T->rchild);}return OK;
}// 递归后序遍历二叉树 T ,输出访问的结点字符序列
Status PostOrderTraverse(BiTree T) {// 左 - 右 - 根if(T) {PostOrderTraverse(T->lchild);PostOrderTraverse(T->rchild);printf("%c ",T->data);}return OK;
}// 栈基本操作
void InitStack(SqStack *S) {S->top = -1;
}// 判断是否空
int StackEmpty(SqStack S) {return S.top == -1;
}// 进栈
void Push(SqStack *S, BiTree e) {if (S->top == MAXSIZE - 1) {printf("栈满\n");return;}S->top++;S->data[S->top] = e;
}// 出栈
BiTree Pop(SqStack *S) {if (StackEmpty(*S)) {printf("栈空\n");return NULL;}BiTree e = S->data[S->top];S->top--;return e;
}BiTree GetTop(SqStack S) {if (StackEmpty(S)) {printf("栈空\n");return NULL;}return S.data[S.top];
}// 非递归先序遍历二叉树 T,依靠栈实现
// 要求在遍历过程中输出访问的结点字符的同时,输出结点进栈/出栈的过程 和 栈中指针所指的结点字符
Status NRPreOrderTraverse(BiTree T) {SqStack S;InitStack(&S);if(T!=NULL) {BiTree p ;S.data[++(S.top)] = T;while(S.top != -1) {// 根节点出栈再找它的子树p = S.data[(S.top)--];printf("出栈 %c \n",p->data);// 右子树压在最底下if(p->rchild != NULL) {S.data[++(S.top)] = p->rchild;}if(p->lchild != NULL) {S.data[++(S.top)] = p->lchild;}}}return OK;
}// 非递归中序遍历二叉树 T  左根右
Status NRInOrderTraverse(BiTree T) {SqStack S;InitStack(&S);BiTree p = T;while (p ||!StackEmpty(S)) {while (p) {//printf("结点 %c 准备进栈 \n", p->data);Push(&S, p);//printf("当前栈顶: %c \n", GetTop(S)->data);//printf("正在访问结点 %c \n", p->data);// 访问左边p = p->lchild;}// 栈不空就出栈if (!StackEmpty(S)) {p = Pop(&S);printf("结点 %c 出栈 \n", p->data);// 访问右边p = p->rchild;}}return OK;
}// 非递归后序遍历二叉树 T  左右根
Status NRPostOrderTraverse(BiTree T) {SqStack S;InitStack(&S);BiTree p = T;BiTree lastVisited = NULL;while (p ||!StackEmpty(S)) {if(p) {S.data[++(S.top)] = p;// 访问左结点p = p->lchild;}else {p = S.data[S.top];// 不急着出栈左结点 看看右节点是否存在以及是否被访问过 压入栈中if (p->rchild != NULL && p->rchild != lastVisited) {p = p->rchild;S.data[++(S.top)] = p;// 查看右结点的左结点p = p ->lchild;}else {p = S.data[(S.top)--];printf("出栈 %c \n",p->data);lastVisited = p;// 在一个结点出栈后,紧接着下一个结点出栈,所以p直接置空p = NULL;}}}return OK;
}// 应用实例1:返回二叉树T度分别为 0 , 1 , 2的结点数
void TNodes(BiTree T, int d, int *count) {if (T) {int degree = (T->lchild!= NULL) + (T->rchild!= NULL);if (degree == d) {(*count)++;}TNodes(T->lchild, d, count);TNodes(T->rchild, d, count);}
}// 应用实例2:求二叉树 T 的高度
int High(BiTree T) {if (T == NULL) return 0;else {int leftHeight = High(T->lchild);int rightHeight = High(T->rchild);return (leftHeight > rightHeight)? (leftHeight + 1) : (rightHeight + 1);}
}// 应用实例3:根据给定的字符序列生成二叉排序树
void CreateBST(BiTree *T, const char *chars) {*T = NULL;int len = strlen(chars);for (int i = 0; i < len; i++) {BiTree p = *T;BiTree q = NULL;while (p!= NULL) {q = p;if (chars[i] < p->data) {p = p->lchild;} else {p = p->rchild;}}BiTree newNode = (BiTree)malloc(sizeof(BiTNode));newNode->data = chars[i];newNode->lchild = newNode->rchild = NULL;if (q == NULL) {*T = newNode;} else if (chars[i] < q->data) {q->lchild = newNode;} else {q->rchild = newNode;}}
}int main() {// (1) 调用CreateBiTree(T)函数生成一棵二叉树TBiTree T;printf("请输入二叉树T的先序遍历序列(#表示空节点):\n");CreateBiTree(&T);printf("先序遍历成功!\n");printf("------------------------------\n");// (2) 分别调用先序遍历、中序遍历和后序遍历的递归函数输出相应的遍历结果printf("递归先序遍历结果:\n");PreOrderTraverse(T);printf("\n");printf("递归中序遍历结果:\n");InOrderTraverse(T);printf("\n");printf("递归后序遍历结果:\n");PostOrderTraverse(T);printf("\n");printf("------------------------------\n");// (3) 分别调用先序遍历、中序遍历和后序遍历的非递归函数输出相应的遍历结果和栈元素的变化过程printf("非递归先序遍历结果及栈变化:\n");NRPreOrderTraverse(T);printf("------------------------------\n");printf("非递归中序遍历结果及栈变化:\n");NRInOrderTraverse(T);printf("------------------------------\n");printf("非递归后序遍历结果及栈变化:\n");NRPostOrderTraverse(T);printf("------------------------------\n");// (4) 调用TNodes(T)函数,输出二叉树T度分别为0、1、2的结点数int count0 = 0, count1 = 0, count2 = 0;TNodes(T, 0, &count0);TNodes(T, 1, &count1);TNodes(T, 2, &count2);printf("度为0的节点个数:%d\n", count0);printf("度为1的节点个数:%d\n", count1);printf("度为2的节点个数:%d\n", count2);printf("------------------------------\n");// (5) 调用CreateBST(T1,"DBFCAEG"),CreateBST(T2,"ABCDEFG"),创建两棵二叉树,对它们进行中序遍历,并调用High()函数输出其高度BiTree T1, T2;CreateBST(&T1, "DBFCAEG");CreateBST(&T2, "ABCDEFG");printf("T1中序遍历结果:");InOrderTraverse(T1);printf("\nT1高度:%d\n", High(T1));printf("T2中序遍历结果:");InOrderTraverse(T2);printf("\nT2高度:%d\n", High(T2));return 0;
}

相关文章:

【C语言】二叉树(BinaryTree)的创建、3种递归遍历、3种非递归遍历、结点度的实现

代码主要实现了以下功能&#xff1a; 二叉树相关数据结构定义 定义了二叉树节点结构体 BiTNode&#xff0c;包含节点数据值&#xff08;字符类型&#xff09;以及指向左右子树的指针。 定义了顺序栈结构体 SqStack&#xff0c;用于存储二叉树节点指针&#xff0c;实现非递归遍历…...

2024年11月文章一览

2024年11月编程人总共更新了21篇文章&#xff1a; 1.2024年10月文章一览 2.《使用Gin框架构建分布式应用》阅读笔记&#xff1a;p307-p392 3.《使用Gin框架构建分布式应用》阅读笔记&#xff1a;p393-p437 4.《使用Gin框架构建分布式应用》读后感 5.《Django 5 By Example…...

重生之我在异世界学编程之C语言:二维数组篇

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文一 二维数组的创建1. 二维数组的…...

和鲸科技创始人CEO范向伟出席首届工业智算产业发展研讨会,共话 AI 创新与产业化落地

11 月 22 日&#xff0c;首届工业智算产业发展研讨会在中国工业互联网研究院召开。工业和信息化部党组成员、副部长单忠德&#xff0c;国家信息中心大数据发展部副主任魏颖出席会议并致辞。中国工程院院士、北京化工大学教授高金吉&#xff0c;工业和信息化部信息通信发展司二级…...

postgres数据备份与主从配置

备份PostgreSQL数据库 备份格式有几种选择&#xff1a; bak&#xff1a;压缩二进制格式 sql&#xff1a;明文转储 tar: tarball mydb# \q -bash-4.2$ pg pgawk pg_dump pgrep pg_basebackup pg_dumpall pg_restore# 备份所有的 -bash-4.2$ pg_dumpall &…...

【二分查找】力扣 275. H 指数 II

一、题目 二、思路 h 指数是高引用引用次数&#xff0c;而 citations 数组中存储的就是不同论文被引用的次数&#xff0c;并且是按照升序排列的。也就是说 h 指数将整个 citations 数组分成了两部分&#xff0c;左半部分是不够引用 h 次 的论文&#xff0c;右半部分论文的引用…...

使用uni-app进行开发前准备

使用uni-app进行开发&#xff0c;需要遵循一定的步骤和流程。以下是一个详细的指南&#xff0c;帮助你开始使用uni-app进行开发&#xff1a; 一、开发环境搭建 安装Node.js&#xff1a; 首先&#xff0c;从Node.js的官方网站&#xff08;https://nodejs.org/&#xff09;下载并…...

AI开发-深度学习框架-PyTorch-torchnlp

1 需求 Welcome to Pytorch-NLP’s documentation! — PyTorch-NLP 0.5.0 documentation 2 接口 3 示例 4 参考资料...

VBA数据库解决方案第十七讲:Recordset对象记录位置的定位方法

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...

Ubuntu 操作系统

一、简介 Ubuntu 是一个基于 Linux 的开源操作系统&#xff0c;它由 Canonical Ltd. 公司维护和资助。Ubuntu 以其易用性、强大的社区支持和定期的安全更新而闻名&#xff0c;一个一桌面应用为主的操作系统。 二、用户使用 1、常规用户的登陆方式 在登录时一般使用普通用户&…...

Maven 内置绑定到底怎么回事?

Maven是一个很好的项目管理工具. 一方面有着众多脚手架&#xff0c;另一方面在依赖管理方面 帮助使用者做了很多准备工作. 随着Maven的使用和学习的深入&#xff0c;大家会不仅有一些问题。 比较浅显的一个就是&#xff0c; 日常我们的Maven 下载安装好以后&#xff0c;在IDE 里…...

如何把Qt exe文件发送给其他人使用

如何把Qt exe文件发送给其他人使用 1、先把 Debug改成Release2、重新构建项目3、运行项目4、找到release文件夹5、新建文件夹&#xff0c;存放exe文件6、打开qt控制台串口7、下载各种文件8、压缩&#xff0c;发送压缩包给别人 1、先把 Debug改成Release 2、重新构建项目 3、运行…...

【汇编语言】call 和 ret 指令(三) —— 深度解析汇编语言中的批量数据传递与寄存器冲突

文章目录 前言1. 批量数据的传递1.1 存在的问题1.2 如何解决这个问题1.3 示例演示1.3.1 问题说明1.3.2 程序实现 2. 寄存器冲突问题的引入2.1 问题引入2.2 分析与解决问题2.2.1 字符串定义方式2.2.2 分析子程序功能2.2.3 得到子程序代码 2.3 子程序的应用2.3.1 示例12.3.2 示例…...

定义函数合并字符串—超详细讲解

【问题描述】 编写一个函数void str_bin(char str1[ ], char str2[ ])&#xff0c; str1、str2是两个有序字符串&#xff08;其中字符按ASCII码从小到大排序&#xff09;&#xff0c;将str2合并到字符串str1中&#xff0c;要求合并后的字符串仍是有序的&#xff0c;允许字符重…...

实现 vue3 正整数输入框组件

1.实现代码 components/InputInteger.vue <!-- 正整数输入框 --> <template><el-input v-model"_value" input"onInput" maxlength"9" clearable /> </template><script lang"ts" setup> import { ref …...

Leetcode - 周赛425

目录 一&#xff0c;3364. 最小正和子数组 二&#xff0c; 3365. 重排子字符串以形成目标字符串 三&#xff0c;3366. 最小数组和 四&#xff0c;3367. 移除边之后的权重最大和 一&#xff0c;3364. 最小正和子数组 本题可以直接暴力枚举&#xff0c;代码如下&#xff1a; …...

c++(斗罗大陆2)

我把魂力等级更新到了31级 #include<iostream> #include<conio.h> #include<windows.h> #include<stdlib.h> #include<stdio.h> #include<time.h> #include<string.h> using namespace std; int qs10; int xthl0;//先…...

redis常见数据类型

Redis是一个开源的、内存中的数据结构存储系统&#xff0c;它可以用作数据库、缓存和消息代理&#xff0c;支持多种数据类型。 一、数据类型介绍 String&#xff08;字符串&#xff09; Redis中最基本的数据类型。可以存储任何类型的数据&#xff0c;包括字符串、数字和二进制…...

MySQL - 性能优化

使用 Explain 进行分析 Explain 用来分析 SELECT 查询语句&#xff0c;开发人员可以通过分析 Explain 结果来优化查询语句。 比较重要的字段有: select_type : 查询类型&#xff0c;有简单查询、联合查询、子查询等 key : 使用的索引 rows : 扫描的行数 type &#xff1a;…...

Linux进程概念-详细版(一)

目录 进程概念 描述进程-PCB task_struct-PCB的一种 task_struct内容分类 查看进程 通过系统目录查看 通过ps命令查看 通过系统调用获取进程的PID和PPID 通过系统调用创建进程 fork的认识 使用if进行分流 最后的总结 Linux进程状态 运行状态-R 浅度睡眠状态-S 深度睡…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考

目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候&#xff0c;显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...