二叉树的先序、中序、后序遍历-非递归实现
1.头文件及类型定义
#include<stdio.h>
#include<stdlib.h>
#define ElemType BiTNode*
#define ElemType1 char
2.二叉链表结点类型定义
//二叉树结点类型定义
typedef struct BiTNode {
ElemType1 data; //结点中的数据域
struct BiTNode* lchild, * rchild; //左右孩子指针
}BiTNode, * BiTree;
//辅助栈类型定义
typedef struct LinkStackNode { //链栈类型定义
ElemType data; //数据域
struct LinkStackNode* next; //指针域
}SNode, * LiStack;
3.函数声明
/*函数声明*/
void CreateBiTree(BiTree& T); //1.先序建立二叉树
bool InitLinkStack(LiStack& S); //2.初始化链栈
bool LiStackEmpty(LiStack S); //3.判空
bool Push(LiStack& S, ElemType e); //4.入栈
bool Pop(LiStack& S, ElemType& e); //5.出栈
bool GetTop(LiStack S, ElemType& e); //6.获取栈顶元素
void visit(BiTNode* p); //7.打印结点值
void PreOrder(BiTree T); //8.先序遍历
void InOrder(BiTree T); //9.中序遍历
void PostOrder(BiTree T); //10.后序遍历
4.基本操作
4.1 先序建立二叉树
//1.先序建立二叉树
void CreateBiTree(BiTree& T) {
char c;
scanf("%c", &c);
if (c == '#')
T = NULL;
else {
T = (BiTNode*)malloc(sizeof(BiTNode));
T->data = c;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
4.2 初始化栈
//2.初始化栈
bool InitLinkStack(LiStack& S) {
S = (SNode*)malloc(sizeof(SNode)); //分配头结点
if (S == NULL)
return false; //内存不足,分配失败
S->next = NULL; //头结点之后暂时没有结点
return true;
}
4.3 判空
//3.判空
bool LiStackEmpty(LiStack S) {
return (S->next == NULL);
}
4.4 入栈
//4.入栈
bool Push(LiStack& S, ElemType e) {
SNode* p = (SNode*)malloc(sizeof(SNode));
if (p == NULL) //内存分配失败
return false;
p->data = e;
p->next = S->next;
S->next = p;
return true;
}
4.5 出栈
//5.出栈
bool Pop(LiStack& S, ElemType& e) {
if (S->next == NULL)
return false; //栈空,报错
SNode* q = S->next; //找到当前链栈的栈顶结点
e = q->data; //返回栈顶结点的值
S->next = q->next;
free(q);
return true;
}
4.6 读取栈顶元素
//6.读取栈顶元素操作
bool GetTop(LiStack S, ElemType& e) {
if (S->next == NULL)
return false; //栈空,报错
e = S->next->data;
return true;
}
4.7 打印结点
//7.打印结点-用于遍历
void visit(BiTNode* p) {
printf("%c\t", p->data);
}
4.8 先序遍历★★★
//8.先序遍历
void PreOrder(BiTree T) {
LiStack S; //声明一个链栈
InitLinkStack(S); //初始化栈
BiTree p = T; //p是遍历指针
while (p || !LiStackEmpty(S)) { //栈不空或者p不空时循环
if (p) { //一路向左
visit(p); //访问当前结点
Push(S, p); //当前结点入栈
p = p->lchild; //左孩子不空,一直向左
}
else { //出栈,并转向出栈结点的右子树
Pop(S, p); //栈顶元素出栈
p = p->rchild; //向右子树走,p赋值为当前结点右孩子
}//返回while循环继续进入if-else语句
}
}
4.9 中序遍历★★★
//9.中序遍历
void InOrder(BiTree T) {
LiStack S; //声明一个链栈
InitLinkStack(S); //初始化栈
BiTree p = T; //p是遍历指针
while (p || !LiStackEmpty(S)) { //栈不空或者p不空时循环
if (p) { //一路向左
Push(S, p); //当前结点入栈
p = p->lchild; //左孩子不空,一直向左
}
else { //出栈,并转向出栈结点的右子树
Pop(S, p); //栈顶元素出栈
visit(p); //访问出栈结点
p = p->rchild; //向右子树走,p赋值为当前结点右孩子
}//返回while循环继续进入if-else语句
}
}
4.10 后序遍历★★★
//10.后序遍历
void PostOrder(BiTree T) {
LiStack S; //声明一个链栈
InitLinkStack(S); //初始化栈
BiTree p = T; //p是遍历指针
BiTNode* r = NULL; //辅助指针,指向最近访问过的结点,用于记录是否已被访问
while (p || !LiStackEmpty(S)) { //栈不空或者p不空时循环
if (p) {/*一路向左*/
Push(S, p); //当前结点入栈
p = p->lchild; //左孩子不空,一直向左
}
else {/*左空,向右*/
GetTop(S, p); //获取栈顶元素
if (p->rchild && p->rchild != r) {/*若右子树存在,且未被访问过*/
p = p->rchild; //转向右
Push(S, p); //压入栈
p = p->lchild; //再走到最左
}
else {/*否则,弹出结点并访问*/
Pop(S, p); //栈顶元素出栈
visit(p); //访问出栈结点
r = p; //记录最近访问过的结点
p = NULL; //结点访问完后,重置p指针
}
}//else
}//while
}
4.11 main函数
int main() {
BiTree T; //声明一个二叉树
/*1、先序创建二叉树*/
printf("先序创建二叉树:");
CreateBiTree(T); //先序建立二叉树
/*2、先序遍历二叉树*/
printf("<————先序遍历————>\n");
PreOrder(T);
/*3、中序遍历二叉树*/
printf("\n<————中序遍历————>\n");
InOrder(T);
/*4、后序遍历二叉树*/
printf("\n<————后序遍历————>\n");
PostOrder(T);
return 0;
}
4.12 测试
4.12.1 二叉树结构

4.12.2 测试结果

5.小结
无论是递归实现二叉树的三种遍历还是非递归实现二叉树的三种遍历,都要借助栈的支持。
- 使用递归算法时,隐含了递归栈,这个栈是系统调用的
- 使用非递归算法时,则需要自己实现一个栈并实现其相关操作
【注】
- 先序序列和中序序列的关系相当于:
以先序序列入栈,以中序序列出栈
本文详细介绍了如何非递归地实现二叉树的先序、中序和后序遍历,通过初始化栈、入栈、出栈等操作,阐述了非递归遍历的实现过程,并提供了测试结果。
625

被折叠的 条评论
为什么被折叠?



