【数据结构二叉树】C非递归算法实现二叉树的先序、中序、后序遍历

引言:

遍历二叉树:指按某条搜索路径巡访二叉树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。
除了层次遍历外,二叉树有三个重要的遍历方法:先序遍历、中序遍历、后序遍历。
1、递归算法实现先序、中序、后序遍历:

(1)先序遍历:

void PreOrderTraverse(BiTree T)
{if(T){cout<<T->data;PreOrderTraverse(T->lchild);PreOrderTraverse(T->rchild);}
}

(2)中序遍历:

void InOrderTraverse(BiTree T)
{   if(T){InOrderTraverse(T->lchild);cout<<T->data;InOrderTraverse(T->rchild);}
} 

(3)后序遍历

void PostOrderTraverse(BiTree T)
{   if(T){  PostOrderTraverse(T->lchild); PostOrderTraverse(T->rchild); cout<<T->data;   }
} 

2.非递归算法实现先序、中序、后序遍历:

采用非递归算法则需要利用栈来实现对二叉树的遍历:
(1)先序遍历非递归算法

void  PreOrder_non_recursion(BiTree T)//先序遍历的非递归算法 
{LinkStack S;InitStack (S);   BiTree p,q;p=T;while(p||!StackEmpty(S)){if(p){Push(S,*p); cout<<p->data; //访问根节点 p=p->lchild;   //遍历左子树 }else{Pop(S,*q);p=q->rchild;   //遍历右子树 }}
}

(2)中序遍历非递归算法

void  InOrder_non_recursion(BiTree T)//中序遍历的非递归算法 
{LinkStack S;InitStack (S);   BiTree p;    BiTree q; p=T;while(p||!StackEmpty(S)){if(p){Push(S,*p); p=p->lchild;   //遍历左子树 }else{Pop(S,*q);cout<<q->data; //访问根节点 p=q->rchild;   //遍历右子树 }}
}

(3)后序遍历非递归算法
(采用非递归算法实现对二叉树的后序遍历,会稍微复杂一些,本算法借用了两个栈结构)

void  PostOrder_non_recursion(BiTree T)//后序遍历的非递归算法 
{LinkStack l_S,r_S;InitStack (l_S);InitStack (r_S);BiTree p,q;    p=T;Push(l_S,*p);while(!StackEmpty(l_S)){Pop(l_S, *q);Push(r_S,*q);if(q->lchild){Push(l_S, *q->lchild);}if(q->rchild){Push(l_S,*q->rchild);}}while(!StackEmpty(r_S)){Pop(r_S,*q);cout<<q->data;}
}

3.完整代码

1、采用按照先序遍历的顺序建立二叉链表,用‘#’表示空树。如图所示:
在这里插入图片描述
2、先序遍历的递归与非递归算法的对比:

#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
using namespace std;
typedef char TElemType;
typedef int Status;typedef struct BiTNode{  //二叉树的存储结构TElemType   data;	// 数据域struct  BiTNode *lchild; //左孩子指针struct  BiTNode *rchild; //右孩子指针
}BiTNode, *BiTree;typedef struct StackNode {  //栈的存储结构BiTNode data;       //栈数据元素类型为树结点型 struct StackNode *next;
} StackNode, *LinkStack;Status InitStack(LinkStack &S) { //栈初始化S = NULL;return OK;
}Status Push(LinkStack &S, BiTNode e) { //入栈LinkStack p;p = new StackNode; //生成新结点if (!p) {return OVERFLOW;}p->data = e; //将新结点数据域置为ep->next = S; //将新结点插入栈顶S = p; //修改栈顶指针为preturn OK;
}Status Pop(LinkStack &S, BiTNode &e) {  //出栈LinkStack p;if (S == NULL)return ERROR; //栈空e = S->data; //将栈顶元素赋给ep = S; //用p临时保存栈顶元素空间,以备释放S = S->next; //修改栈顶指针delete p; //释放原栈顶元素的空间return OK;
}bool StackEmpty(LinkStack S) {  //判断是否空栈if (!S)return true;return false;
}void CreateBiTree_PreOrder(BiTree &T){ //以先序次序创建二叉树 char ch; cin>>ch;if(ch=='#')T=NULL; else{T=new BiTNode;  //生成根结点T->data=ch; //根结点的数据域置为chCreateBiTree_PreOrder(T->lchild);//构造左子树CreateBiTree_PreOrder(T->rchild); //构造右子树}}void PreOrder(BiTree T){   //先序遍历的递归递归算法if(T){cout<<T->data;PreOrder(T->lchild);PreOrder(T->rchild);}
}void  PreOrder_non_recursion(BiTree T)//先序遍历的非递归算法 
{LinkStack S;InitStack (S);   BiTree p,q;p=T;while(p||!StackEmpty(S)){if(p){Push(S,*p); cout<<p->data; //访问根节点 p=p->lchild;   //遍历左子树 }else{Pop(S,*q);p=q->rchild;   //遍历右子树 }}
}int main() {BiTree T;cout<<"以先序次序创建二叉链表,以#表示空子树:"<<endl;CreateBiTree_PreOrder(T);cout<<"先序序列(递归算法):"; PreOrder(T); cout<<"\n先序序列(非递归算法):"; PreOrder_non_recursion(T);return 0;
}

实验结果:
在这里插入图片描述
3、中序遍历的递归与非递归算法的对比:

#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
using namespace std;
typedef char TElemType;
typedef int Status;typedef struct BiTNode{  //二叉树的存储结构TElemType   data;	// 数据域struct  BiTNode *lchild; //左孩子指针struct  BiTNode *rchild; //右孩子指针
}BiTNode, *BiTree;typedef struct StackNode {  //栈的存储结构BiTNode data;       //栈数据元素类型为树结点型 struct StackNode *next;
} StackNode, *LinkStack;Status InitStack(LinkStack &S) { //栈初始化S = NULL;return OK;
}Status Push(LinkStack &S, BiTNode e) { //入栈LinkStack p;p = new StackNode; //生成新结点if (!p) {return OVERFLOW;}p->data = e; //将新结点数据域置为ep->next = S; //将新结点插入栈顶S = p; //修改栈顶指针为preturn OK;
}Status Pop(LinkStack &S, BiTNode &e) {  //出栈LinkStack p;if (S == NULL)return ERROR; //栈空e = S->data; //将栈顶元素赋给ep = S; //用p临时保存栈顶元素空间,以备释放S = S->next; //修改栈顶指针delete p; //释放原栈顶元素的空间return OK;
}bool StackEmpty(LinkStack S) {  //判断是否空栈if (!S)return true;return false;
}void CreateBiTree_PreOrder(BiTree &T){ //以先序次序创建二叉树 char ch; cin>>ch;if(ch=='#')T=NULL; else{T=new BiTNode;  //生成根结点T->data=ch; //根结点的数据域置为chCreateBiTree_PreOrder(T->lchild);//构造左子树CreateBiTree_PreOrder(T->rchild); //构造右子树}}void InOrder(BiTree T){   //中序遍历的递归递归算法if(T){InOrder(T->lchild);cout<<T->data;InOrder(T->rchild);}
}void  InOrder_non_recursion(BiTree T)//中序遍历的非递归算法 
{LinkStack S;InitStack (S);   BiTree p;    BiTree q; p=T;while(p||!StackEmpty(S)){if(p){Push(S,*p); p=p->lchild;   //遍历左子树 }else{Pop(S,*q);cout<<q->data; //访问根节点 p=q->rchild;   //遍历右子树 }}
}int main() {BiTree T;cout<<"以先序次序创建二叉链表,以#表示空子树:"<<endl;CreateBiTree_PreOrder(T);cout<<"中序序列(递归算法):"; InOrder(T); cout<<"\n中序序列(非递归算法):"; InOrder_non_recursion(T);return 0;
}

实验结果:
在这里插入图片描述

4、后序遍历的递归与非递归算法的对比:

#include<iostream>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
using namespace std;
typedef char TElemType; 
typedef int Status;typedef struct BiTNode{  //二叉树的存储结构TElemType   data;	// 数据域struct  BiTNode *lchild; //左孩子指针struct  BiTNode *rchild; //右孩子指针
}BiTNode, *BiTree;typedef struct StackNode {  //栈的存储结构BiTNode data;       //栈数据元素类型为树结点型 struct StackNode *next;
} StackNode, *LinkStack;Status InitStack(LinkStack &S) { //栈初始化S = NULL;return OK;
}Status Push(LinkStack &S, BiTNode e) { //入栈LinkStack p;p = new StackNode; //生成新结点if (!p) {return OVERFLOW;}p->data = e; //将新结点数据域置为ep->next = S; //将新结点插入栈顶S = p; //修改栈顶指针为preturn OK;
}Status Pop(LinkStack &S, BiTNode &e) {  //出栈LinkStack p;if (S == NULL)return ERROR; //栈空e = S->data; //将栈顶元素赋给ep = S; //用p临时保存栈顶元素空间,以备释放S = S->next; //修改栈顶指针delete p; //释放原栈顶元素的空间return OK;
}bool StackEmpty(LinkStack S) {  //判断是否空栈if (!S)return true;return false;
}void CreateBiTree_PreOrder(BiTree &T){ //以先序次序创建二叉树 char ch; cin>>ch;if(ch=='#')T=NULL; else{T=new BiTNode;  //生成根结点T->data=ch; //根结点的数据域置为chCreateBiTree_PreOrder(T->lchild);//构造左子树CreateBiTree_PreOrder(T->rchild); //构造右子树}}void PostOrder(BiTree T){   //后序遍历的递归递归算法if(T){PostOrder(T->lchild);PostOrder(T->rchild);cout<<T->data;}
}void  PostOrder_non_recursion(BiTree T)//后序遍历的非递归算法 
{LinkStack l_S,r_S;InitStack (l_S);InitStack (r_S);BiTree p,q;    p=T;Push(l_S,*p);while(!StackEmpty(l_S)){Pop(l_S, *q);Push(r_S,*q);if(q->lchild){Push(l_S, *q->lchild);}if(q->rchild){Push(l_S,*q->rchild);}}while(!StackEmpty(r_S)){Pop(r_S,*q);cout<<q->data;}
}int main() {BiTree T;cout<<"以先序次序创建二叉链表,以#表示空子树:"<<endl;CreateBiTree_PreOrder(T);cout<<"后序序列(递归算法):"; PostOrder(T); cout<<"\n后序序列(非递归算法):"; PostOrder_non_recursion(T);return 0;
}

实验结果:
在这里插入图片描述

4.结语

对于先序、中序和后序遍历,如果采用非递归算法,则需要借助栈来实现。对于二叉树而言,还有一种大家更为熟知的遍历方式,那就是层次遍历。实现对二叉树的层次遍历,则需要借助队列来实现。实现对二叉树的层次遍历,可以参考C实现二叉树的层次遍历
欢迎大家一起来交流~

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

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

相关文章

深入学习 Scrapy 框架:从入门到精通的全面指南

深入学习 Scrapy 框架&#xff1a;从入门到精通的全面指南 引言 在数据驱动的时代&#xff0c;网络爬虫成为了获取信息的重要工具。Scrapy 是一个强大的 Python 爬虫框架&#xff0c;专为快速高效地提取网页数据而设计。本文将深入探讨 Scrapy 的使用&#xff0c;从基础知识到…

蓝桥杯 区间移位--二分、枚举

题目 代码 #include <stdio.h> #include <string.h> #include <vector> #include <algorithm> #include <iostream> using namespace std; struct node{ int a,b; }; vector<node> q; bool cmp(node x,node y){ return x.b <…

SpringBoot+VUE2完成WebSocket聊天(数据入库)

下载依赖 <!-- websocket --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!-- MybatisPlus --><dependency><groupId>com.ba…

图文深入介绍Oracle DB link(一)

1. 引言&#xff1a; 本文图文深入介绍Oracle DB link&#xff0c;先介绍基本概念。 2.DB link的定义 数据库链接&#xff08;Database Link&#xff0c;简称 DB Link&#xff09;是 Oracle 数据库中的一个重要功能。它是一种在一个 Oracle 数据库实例中访问另一个 Oracle 数…

MoonBit 双周报 Vol.59:新增编译器常量支持,改进未使用警告,支持跨包函数导入...多个关键技术持续优化中!

2024-11-04 MoonBit更新 增加了编译期常量的支持。常量的名字以大写字母开头&#xff0c;用语法 const C ... 声明。常量的类型必须是内建的数字类型或 String。常量可以当作普通的值使用&#xff0c;也可以用于模式匹配。常量的值目前只能是字面量&#xff1a; const MIN_…

HTB:Shocker[WriteUP]

目录 连接至HTB服务器并启动靶机 1.How many TCP ports are listening on Shocker? 使用nmap对靶机TCP端口进行开放扫描 2.What is the name of the directory available on the webserver that is a standard name known for running scripts via the Common Gateway Int…

力扣——另一个的子树(C语言)

1.题目&#xff1a; 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree …

【C++】对左值引用右值引用的深入理解(右值引用与移动语义)

&#x1f308; 个人主页&#xff1a;谁在夜里看海. &#x1f525; 个人专栏&#xff1a;《C系列》《Linux系列》 ⛰️ 天高地阔&#xff0c;欲往观之。 ​ 目录 前言&#xff1a;对引用的底层理解 一、左值与右值 提问&#xff1a;左值在左&#xff0c;右值在右&#xff1f;…

解决 ClickHouse 高可用集群中 VRID 冲突问题:基于 chproxy 和 keepalived 的实践分析

Part1背景描述 近期&#xff0c;我们部署了两套 ClickHouse 生产集群&#xff0c;分别位于同城的两个数据中心。这两套集群的数据保持一致&#xff0c;以便在一个数据中心发生故障时&#xff0c;能够迅速切换应用至另一个数据中心的 ClickHouse 实例&#xff0c;确保服务连续性…

B2C电商平台如何提升转化率 小程序商城如何做好运营

在竞争激烈的电商市场中&#xff0c;提升转化率是每个B2C电商平台的重要目标。转化率直接影响销售业绩和盈利能力&#xff0c;因此&#xff0c;了解如何优化用户体验、增强客户信任和提高购买动机是至关重要的。商淘云分享一些有效的策略&#xff0c;帮助B2C电商平台提升转化率…

RK3568平台开发系列讲解(字符设备驱动篇)Linux设备分类

🚀返回专栏总目录 文章目录 一、字符设备(是以字节为单位进行输入输出)二、块设备:块设备是以块为单位进行输入输出三、网络设备沉淀、分享、成长,让自己和他人都能有所收获!😄 一、字符设备(是以字节为单位进行输入输出) 串口、鼠标 字符设备没有固定的大小,也没…

STM32Fxx读写eeprom(AT24C16)

一.I2C 协议简介 I2C 通讯协议 (Inter &#xff0d; Integrated Circuit) 是由 Phiilps 公司开发的&#xff0c;由于它引脚少&#xff0c;硬件实现简单&#xff0c;可扩展性强&#xff0c;不需要 USART、CAN 等通讯协议的外部收发设备&#xff0c;现在被广泛地使用在系统内多个…

idea使用Translation插件实现翻译

1.打开idea&#xff0c;settings&#xff0c;选择plugins&#xff0c;搜索插件Translation&#xff0c;安装 2.选择翻译引擎 3.配置引擎&#xff0c;以有道词典为例 3.1 获取应用ID&#xff0c;应用秘钥 3.1.1 创建应用 点击进入有道智云控制台 3.1.2 复制ID和秘钥 3.2 idea设…

【论文精读】LPT: Long-tailed prompt tuning for image classification

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;论文精读_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 摘要 2. …

【SQL Server】解决因使用 varchar 类型存储 Unicode 字符串导致的中文显示乱码问题

问题描述 导入 SQL 到 SQL Server 数据库后&#xff0c;存在部分列的中文显示异常的问题。 原因分析 观察发现显示异常的字段的数据类型是 varchar&#xff0c;而显示正常的字段的数据类型是 nvarchar。 而且&#xff0c;SQL 文件中所有字符串前面都带有 N 的前缀。 在 SQL 中…

dify实战案例分享-基于多模态模型的发票识别

1 什么是dify Dify是一个开源的大语言模型&#xff08;LLM&#xff09;应用开发平台&#xff0c;旨在简化和加速生成式AI应用的创建和部署。它结合了后端即服务&#xff08;Backend as Service, BaaS&#xff09;和LLMOps的理念&#xff0c;使开发者能够快速搭建生产级的AI应用…

电机控制储备知识 一 电机驱动本质分析以及磁相关的使用场景

一&#xff1a;电机旋转的原因 1.电机基本认识 &#xff08;1&#xff09;电机是一种动力装置&#xff0c;能够将电能转换为动能 电机拥有体积小 、动力足&#xff0c;控制精细灵活的特点 完整的电机系统&#xff1a;电机&#xff08;减速器 传感器&#xff09; 电机驱动器&a…

ubuntu交叉编译dbus库给arm平台使用

1.下载dbus库源码 https://www.freedesktop.org/wiki/Software/dbus 克隆源码: https://gitlab.freedesktop.org/dbus/dbus/-/tree/dbus-1.12?ref_type=heads 下载1.12.20版本: 指定pkgconfig环境变量: export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$PWD/../expat-2.3.…

推荐一款音乐神器:想听就听,想下就下~

在这个音乐充斥生活的时代&#xff0c;你是否也曾想过&#xff0c;有一款软件可以随时随地畅听你喜欢的音乐&#xff1f;今天&#xff0c;我要向你推荐一款令人心动的音乐神器——MusicFree&#xff0c;让你真正体验“想听就听&#xff0c;想下就下”的乐趣&#xff01; 那么&a…

aws(学习笔记第十课) 对AWS的EBS如何备份(snapshot)以及使用snapshot恢复数据,AWS实例存储

aws(学习笔记第十课) 对AWS的EBS如何备份&#xff08;snapshot&#xff09;以及使用snapshot&#xff0c;AWS实例存储 学习内容&#xff1a; 对AWS的EBS如何备份AWS实例存储EBS和实例存储的不足 1. 对AWS的EBS如何备份&#xff08;snapshot&#xff09;以及使用snapshot恢复数…