数据结构---------二叉树前序遍历中序遍历后序遍历
以下是用C语言实现二叉树的前序遍历、中序遍历和后序遍历的代码示例,包括递归和非递归(借助栈实现)两种方式:
1. 二叉树节点结构体定义
#include <stdio.h>
#include <stdlib.h>// 二叉树节点结构体
typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
} TreeNode;
2. 前序遍历
(ps:图来自一位前辈,非常感谢无商用)
2.1 递归方式
// 前序遍历递归函数
void preorderTraversalRecursive(TreeNode* root) {if (root == NULL) {return;}printf("%d ", root->val);preorderTraversalRecursive(root->left);preorderTraversalRecursive(root->right);
}
解释:
- 首先判断根节点是否为空(
NULL
),如果为空,说明已经遍历完或者二叉树本身就是空树,直接返回,不做任何操作。 - 若根节点不为空,则先输出根节点的值(通过
printf
函数),这符合前序遍历“根节点、左子树、右子树”的顺序。 - 接着递归调用
preorderTraversalRecursive
函数去遍历左子树,完成左子树的前序遍历。 - 最后再递归调用该函数遍历右子树,完成整个二叉树的前序遍历。
2.2 非递归方式(借助栈实现)
// 前序遍历非递归函数(借助栈)
void preorderTraversalNonRecursive(TreeNode* root) {if (root == NULL) {return;}struct TreeNode *stack[100]; // 简单起见,这里假设栈的最大容量为100,可以根据实际情况调整int top = -1;stack[++top] = root;while (top >= 0) {TreeNode* current = stack[top--];printf("%d ", current->val);if (current->right!= NULL) {stack[++top] = current->right;}if (current->left!= NULL) {stack[++top] = current->left;}}
}
解释:
- 同样先判断根节点是否为空,为空则直接返回。
- 然后创建一个数组来模拟栈(这里简单地定义了固定大小为100的数组作为栈,实际应用中可根据二叉树规模动态分配内存),并初始化栈顶指针
top
为 -1,表示栈为空。 - 将根节点入栈后,进入循环,只要栈不为空(即
top >= 0
):- 取出栈顶元素(
current = stack[top--]
),输出其值,这模拟了访问根节点的操作。 - 按照前序遍历先右后左的顺序将子节点入栈(因为栈是后进先出的数据结构,先入栈右子节点,后入栈左子节点,这样出栈时就能先访问左子树),如果右子节点或左子节点不为空,就将它们依次入栈,以便后续继续遍历。
- 取出栈顶元素(
3. 中序遍历
3.1 递归方式
// 中序遍历递归函数
void inorderTraversalRecursive(TreeNode* root) {if (root == NULL) {return;}inorderTraversalRecursive(root->left);printf("%d ", root->val);inorderTraversalRecursive(root->right);
}
解释:
- 先判断根节点是否为空,为空则返回。
- 按照中序遍历“左子树、根节点、右子树”的顺序,首先递归调用
inorderTraversalRecursive
函数去遍历左子树,确保左子树的节点先被访问。 - 当左子树遍历完后,输出根节点的值。
- 最后再递归调用该函数遍历右子树,完成整个二叉树的中序遍历。
3.2 非递归方式(借助栈实现)
// 中序遍历非递归函数(借助栈)
void inorderTraversalNonRecursive(TreeNode* root) {if (root == NULL) {return;}struct TreeNode *stack[100]; // 假设栈最大容量为100,可按需调整int top = -1;TreeNode* current = root;while (current!= NULL || top >= 0) {while (current!= NULL) {stack[++top] = current;current = current->left;}current = stack[top--];printf("%d ", current->val);current = current->right;}
}
解释:
- 还是先判断根节点是否为空,为空则返回。
- 创建一个栈并初始化栈顶指针,同时用
current
指针指向根节点。 - 进入循环,只要
current
不为空或者栈不为空:- 先通过内层循环将当前节点及其所有左子树节点依次入栈(不断将
current
指向其左子节点并入栈),直到current
为空,这意味着找到了最左边的节点。 - 然后取出栈顶元素(即最左边的节点),输出其值,这模拟了访问根节点的操作(在中序遍历中此时访问的是左子树遍历完后的根节点)。
- 最后将
current
更新为该节点的右子节点,以便继续遍历右子树,重复上述过程,完成中序遍历。
- 先通过内层循环将当前节点及其所有左子树节点依次入栈(不断将
4. 后序遍历
4.1 递归方式
// 后序遍历递归函数
void postorderTraversalRecursive(TreeNode* root) {if (root == NULL) {return;}postorderTraversalRecursive(root->left);postorderTraversalRecursive(root->right);printf("%d ", root->val);
}
解释:
- 首先判断根节点是否为空,为空则返回,不做后续操作。
- 按照后序遍历“左子树、右子树、根节点”的顺序,先递归调用
postorderTraversalRecursive
函数遍历左子树。 - 接着递归调用该函数遍历右子树。
- 最后输出根节点的值,完成整个二叉树的后序遍历。
4.2 非递归方式(借助栈实现)
// 后序遍历非递归函数(借助栈)
void postorderTraversalNonRecursive(TreeNode* root) {if (root == NULL) {return;}struct TreeNode *stack1[100]; // 假设栈1最大容量为100,可按需调整struct TreeNode *stack2[100]; // 假设栈2最大容量为100,可按需调整int top1 = -1, top2 = -1;stack1[++top1] = root;while (top1 >= 0) {TreeNode* current = stack1[top1--];stack2[++top2] = current;if (current->left!= NULL) {stack1[++top1] = current->left;}if (current->right!= NULL) {stack1[++top1] = current->right;}}while (top2 >= 0) {printf("%d ", stack2[top2--]->val);}
}
解释:
- 先判断根节点是否为空,为空则返回。
- 创建两个栈
stack1
和stack2
(这里同样是简单地假设了固定大小为100的数组来模拟栈,实际可按需优化),以及对应的栈顶指针top1
和top2
,并将根节点入stack1
。 - 在第一个循环中:
- 从
stack1
中取出栈顶元素,放入stack2
中,这一步是为了后续能按后序遍历的顺序输出节点。 - 然后按照后序遍历先左后右的顺序将其左子节点和右子节点(如果存在)依次入
stack1
,方便后续处理。
- 从
- 第一个循环结束后,
stack2
中存储的节点顺序就是后序遍历的顺序了,通过第二个循环依次输出stack2
中节点的值,完成二叉树的后序遍历。
你可以使用以下代码来测试这些遍历函数:
int main() {// 构建一个简单的二叉树示例TreeNode* root = (TreeNode*)malloc(sizeof(TreeNode));root->val = 1;root->left = (TreeNode*)malloc(sizeof(TreeNode));root->left->val = 2;root->left->right = (TreeNode*)malloc(sizeof(TreeNode));root->left->right->val = 4;root->right = (TreeNode*)malloc(sizeof(TreeNode));root->right->val = 3;root->right->left = (TreeNode*)malloc(sizeof(TreeNode));root->right->left->val = 5;// 测试前序遍历printf("前序遍历(递归)结果:");preorderTraversalRecursive(root);printf("\n");printf("前序遍历(非递归)结果:");preorderTraversalNonRecursive(root);printf("\n");// 测试中序遍历printf("中序遍历(递归)结果:");inorderTraversalRecursive(root);printf("\n");printf("中序遍历(非递归)结果:");inorderTraversalNonRecursive(root);printf("\n");// 测试后序遍历printf("后序遍历(递归)结果:");postorderTraversalRecursive(root);printf("\n");printf("后序遍历(非递归)结果:");postorderTraversalNonRecursive(root);printf("\n");return 0;
}
在上述main
函数中,构建了一个简单的二叉树示例,然后分别调用不同的遍历函数并输出结果,方便直观地看到不同遍历方式的效果。实际应用中,你可以根据实际的二叉树结构来进行相应的测试和使用这些遍历方法。
相关文章:

数据结构---------二叉树前序遍历中序遍历后序遍历
以下是用C语言实现二叉树的前序遍历、中序遍历和后序遍历的代码示例,包括递归和非递归(借助栈实现)两种方式: 1. 二叉树节点结构体定义 #include <stdio.h> #include <stdlib.h>// 二叉树节点结构体 typedef struct…...

浏览器引入elasticsearch-head插件
elasticsearch-head插件下载: 链接: https://pan.baidu.com/s/1Dz3aU42HZCNg45iJoDOsMg?pwduvhg 提取码: uvhg 1、打开浏览器设置 2、选择拓展程序 3、选择elasticsearch-head插件下载 4、打开es-head插件 5、修改ip 6、登录...

【ELK】Filebeat采集Docker容器日志
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 介绍filebeat是如何工作的 使用部署filebeat 介绍 Filebeat 是一个用于转发和集中日志数据的轻量级传送器。 Filebeat 作为agent安装在服务器上,监视指…...

异步线程池与CountDownLatch
异步线程池 顾名思义,一个专门用来处理异步任务的线程池。可以避免线程的开销以及非阻塞的执行任务。 CountDownLatch 一个同步工具类,用于 让一个或多个线程等待一组操作完成。 业务场景 支付订单时,用户可以使用多张优惠劵,…...

在图像上显示掩码、框和点的通用函数
在图像上显示掩码、框和点的通用函数 背景介绍函数实现与用途1. 显示掩码函数:`show_mask`2. 显示边界框函数:`show_box`3. 在图像上显示点函数:`show_points`4. 综合显示框和点函数:`show_points_and_boxes_on_image`5. 显示掩码并返回图像函数:`show_mask_on_image`6. 显…...

基于Matlab的变压器仿真模型建模方法(11):三相三绕组换流变压器的建模仿真
1.概述 换流变压器是直流输电系统中的关键设备,主要负责连接交流和直流系统,并实现电能的转换与传输。换流变压器在直流输电系统中的主要用途包括:传送电力:将电能从交流系统传输到直流系统或从直流系统传输到交流系统;电压变换:把交流系统电压变换到换流器所需的换相电压…...

代码随想录算法训练营day46|动态规划part12
今天就结束动态规划章节了,以后还要多加练习。 今天的两道题都很有难度,647回文子串的思路非常巧妙,因为用一维dp数组比较难表示子串的起点和终点,所以需要用二维dp数组表示,dp[i][j]表示以i为起点,j为终点…...

【C语言】头文件
所有学习过C语言的朋友都熟悉这样一段代码: #include <stdio.h>int main(int argc, char *argv[]) {return 0; }那么,你真的了解 <stdio.h> 吗? <stdio…...

蓝桥杯——竞赛省赛国赛题分享
目录 一.[蓝桥杯 2013 省 AB] 错误票据 代码如下: 二.[蓝桥杯 2024 省 Java B] 报数游戏 代码如下: 讲解: 三.[蓝桥杯 2014 国 C] 拼接平方数 代码如下: 四.三步问题(递归,上台阶) 代码…...

企业内训|阅读行业产品运营实战训练营-某运营商数字娱乐公司
近日,TsingtaoAI公司为某运营商旗下数字娱乐公司组织的“阅读行业产品运营实战训练营”在杭州落下帷幕。此次训练营由TsingtaoAI资深互联网产品专家程靖主持。该公司的业务骨干——来自内容、市场、业务、产品与技术等跨部门核心岗位、拥有8-10年实战经验的中坚力量…...

低空无人机产教融合技术详解
低空无人机产教融合技术是将无人机技术与教育、产业深度融合的一种新型教育模式,旨在培养既具备理论知识又具备实践能力的无人机专业人才。以下是对这一技术的详细解析: 一、产教融合的背景与意义 1. 背景: 随着无人机技术的快速发展&#…...

springboot中Controller内文件上传到本地以及阿里云
上传文件的基本操作 <form action"/upload" method"post" enctype"multipart/form-data"> <h1>登录</h1> 姓名:<input type"text" name"username" required><br> 年龄…...

Chrome 132 版本开发者工具(DevTools)更新内容
Chrome 132 版本开发者工具(DevTools)更新内容 一、使用 Gemini 调试 Network、Source 和 Performance Chrome 131 可以使用 Gemini 调试 CSS,现在可以调试更多模块了 与元素面板中的右键菜单类似,要打开 AI 辅助面板并开始与 …...

使用Python从阿里云物联网平台获取STM32温度数据
在物联网(IoT)应用中,设备数据的采集与监控至关重要。本文将详细介绍如何使用Python从阿里云物联网平台获取STM32设备的温度数据。我们将从已有的Java代码出发,逐步将其转换为Python,并处理在过程中遇到的问题…...

Spring Boot 声明式事务
Spring Boot中的声明式事务管理主要通过Transactional注解来实现。以下是Transactional注解的一些关键用法和特性: 1. 启用事务管理 在Spring Boot应用中使用Transactional注解之前,需要在启动类或者配置类上添加EnableTransactionManagement注解来启用事…...

websocket 局域网 webrtc 一对一 多对多 视频通话 的示例
基本介绍 WebRTC(Web Real-Time Communications)是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对点(Peer-to-Peer)的连接,实现视频流和&am…...

uniapp-微信小程序调用摄像头
1.uniapp中的index.vue代码 <template><view class"content"><view class"container"><!-- 摄像头组件 --><camera id"camera" device-position"front" flash"off" binderror"onCameraErr…...

鸿蒙学习笔记:用户登录界面
文章目录 1. 提出任务2. 完成任务2.1 创建鸿蒙项目2.2 准备图片资源2.3 编写首页代码2.4 启动应用 3. 实战小结 1. 提出任务 本次任务聚焦于运用 ArkUI 打造用户登录界面。需呈现特定元素:一张图片增添视觉感,两个分别用于账号与密码的文本输入框&#…...

无人机航测系统技术特点!
一、无人机航测系统的设计逻辑 无人机航测系统的设计逻辑主要围绕实现高效、准确、安全的航空摄影测量展开。其设计目标是通过无人机搭载相机和传感器,利用先进的飞行控制系统和数据处理技术,实现对地表信息的全方位、高精度获取。 需求分析࿱…...

《算法ZUC》题目
判断题 ZUC算法LFSR部分产生的二元序列具有很低的线性复杂度。 A.正确 B.错误 正确答案A 单项选择题 ZUC算法驱动部分LFSR的抽头位置不包括( )。 A.s15 B.s10 C.s7 D.s0 正确答案C 单项选择题 ZUC算法比特重组BR层主要使用了软件实现友好的…...

配置flutter 解决andriod studio报错 no device selected
flutter配置好后 明明下载好了模拟器 但是在andriod studio 找不到设备 显示no devices 这个时候需要我们配置一下flutter关联的android sdk的路径和文件夹 就可以解决了 flutter config --android-sdk 自己android studio的路径 这样配置就可以解决了~...

docker搭建Redis集群及哨兵(windows10环境,OSS Cluster)
一、基本概念 Redis:即 "Remote DIctionary Server" ,翻译为“远程字典服务器”。从字面意义上讲,它指的是一个远程的字典服务,意味着它是一个可以远程访问的服务,主要用于存储键值对(key-value pairs&…...

信息化基础知识——数字政府(山东省大数据职称考试)
大数据分析应用-初级 第一部分 基础知识 一、大数据法律法规、政策文件、相关标准 二、计算机基础知识 三、信息化基础知识 四、密码学 五、大数据安全 六、数据库系统 七、数据仓库. 第二部分 专业知识 一、大数据技术与应用 二、大数据分析模型 三、数据科学 数字政府 大数…...

信息安全实训室网络攻防靶场实战核心平台解决方案
一、引言 网络安全靶场,作为一种融合了虚拟与现实环境的综合性平台,专为基础设施、应用程序及物理系统等目标设计,旨在向系统用户提供全方位的安全服务,涵盖教学、研究、训练及测试等多个维度。随着网络空间对抗态势的日益复杂化…...

Nginx主要知识点总结
1下载nginx 到nginx官网nginx: download下载nginx,然后解压压缩包 然后双击nginx.exe就可以启动nginx 2启动nginx 然后在浏览器的网址处输入localhost,进入如下页面说明nginx启动成功 3了解nginx的配置文件 4熟悉nginx的基本配置和常用操作 Nginx 常…...

PySide6程序框架设计
pyside6有一个优点自动适配高分辨ui pyqt5需要自己写这部分逻辑 1、主程序代码 DINGSHI01Main.py # -*- coding: utf-8 -*- import sys,time,copy from PySide6.QtWidgets import QWidget,QApplication from PySide6.QtCore import Qt from PySide6 import QtCore, QtGui, Q…...

「九」HarmonyOS 5 端云一体化实战项目——「M.U.」应用云侧开发云数据库
1 立意背景 M. 代表 “我”,U. 代表 “你”,这是一款用于记录情侣从相识、相知、相恋、见家长、订婚直至结婚等各个阶段美好记忆留存的应用程序。它旨在为情侣们提供一个专属的空间,让他们能够将一路走来的点点滴滴,如初次相遇时…...

记录:virt-manager配置Ubuntu arm虚拟机
virt-manager(Virtual Machine Manager)是一个图形用户界面应用程序,通过libvirt管理虚拟机(即作为libvirt的图形前端) 因为要在Linux arm环境做测试,记录下virt-manager配置arm虚拟机的过程 先在VMWare中…...

clickhouse-介绍、安装、数据类型、sql
1、介绍 ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),使用C语言编写,主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。 OLAP(On-Line A…...

【shell】常用100个shell命令使用讲解
【shell】常用100个shell命令使用讲解 【一】文件操作命令【二】搜索命令【三】目录操作命令【四】权限操作命令【五】网络操作命令【六】进程和系统控制命令【七】文本操作命令【八】压缩与解压命令【九】磁盘使用管理命令【十】包管理命令【十一】进程管理命令【十二】环境变…...