2021-11-09 数据结构第四次上机实验之树与二叉树(递归和非递归先序中序后序遍历)

这篇博客介绍了如何使用C语言建立基于扩展先序遍历序列的二叉链表,并实现了递归的先序、中序、后序遍历。同时,详细探讨了两种非递归后序遍历的算法,一种利用计数器跟踪节点访问次数,另一种通过模拟栈和指针前驱来判断遍历顺序。这两种方法分别展示了不同的思考角度和实现技巧。
摘要由CSDN通过智能技术生成

1、请根据用户输入的“扩展的先序遍历序列”(用小圆点表示空子树),建立二叉链表方式储存的二叉树,递归实现先序、中序、后序遍历

代码如下:

#include<stdio.h>
#include<stdlib.h>

//二叉树的定义
typedef char TElemType;
typedef struct BiTNode {
	TElemType data;
	struct BiTNode* lchid, * rchid;
}BiTNode,*BiTree;

//创建二叉树
void CreateBiTree(BiTree& T) {
	TElemType a;
	TElemType temp;
	scanf("%c", &a);
	temp = getchar();
	if (a == '.')
		T = NULL;
	else {
		if (!(T = (BiTNode *)malloc(sizeof(BiTNode))))exit(0);
		T->data = a;
		CreateBiTree(T->lchid);
		CreateBiTree(T->rchid);
	}
}

//先序遍历
void PreOrderTraverse(BiTree& T) {
	if (T) {
		printf("%c", T->data);
		PreOrderTraverse(T->lchid);
		PreOrderTraverse(T->rchid);
	}
}

//中序遍历
void InOrderTraverse(BiTree& T) {
	if (T) {
		InOrderTraverse(T->lchid);
		printf("%c", T->data);
		InOrderTraverse(T->rchid);
	}
}

//后序遍历
void PostOrderTraverse(BiTree& T) {
	if (T) {
		PostOrderTraverse(T->lchid);
		PostOrderTraverse(T->rchid);
		printf("%c", T->data);
	}
}


int main() {
	BiTree T;
	printf("请输入二叉树数据:\n");
	CreateBiTree(T);
	printf("先序遍历结果为:\n");
	PreOrderTraverse(T);
	printf("\n中序遍历结果为:\n");
	InOrderTraverse(T);
	printf("\n后序遍历结果为:\n");
	PostOrderTraverse(T);
}

运行结果如下:


  2、请根据用户输入的“扩展的先序遍历序列”(用小圆点表示空子树),建立二叉链表方式储存的二叉树,写出后序遍历该二叉树的非递归算法(11.19更新第二种思路)

第一种思路:(后序)用一个计数器来记录是第几次经过根节点,第一次则再把根节点push进栈中,第二次则可以访问。

本思路对栈的基本操作完整定义写法要求较高函数较多,但理解相对容易

代码如下:(我先序中序后序都写了)

#include<stdio.h>
#include<stdlib.h>

#define STACK_INIT_SIZE 100
//二叉树定义
typedef char TElemType;
typedef struct BiTNode {
	TElemType data;
	int cnt;//后序遍历子树的根节点在第一次遍历时不输出,只有在第二次遍历时才输出,cnt用于记录遍历次数
	struct BiTNode* lchid, * rchid;
}BiTNode, * BiTree;

//定义储存树类型地址的栈
typedef struct Stack {
	BiTree* elem;
	int top;
}SqStack;

//栈初始化
void InitStack(SqStack& S) {
	S.elem = (BiTree*)malloc(STACK_INIT_SIZE * sizeof(BiTree));
	if (!S.elem)exit(0);
	S.top = 0;
}

//判断栈空
bool StackEmpty(SqStack S) {
	if (S.top == 0)
		return true;
	return false;
}

//入栈
void Push(SqStack& S, BiTree e) {
	S.elem[S.top++] = e;
}

//出栈
BiTree Pop(SqStack& S) {
	if (!StackEmpty(S))
		return S.elem[--S.top];
}

//创建树
void CreateBiTree(BiTree& T) {
	TElemType a;
	TElemType temp;
	scanf("%c", &a);
	temp = getchar();
	if (a == '.')
		T = NULL;
	else {
		if (!(T = (BiTNode*)malloc(sizeof(BiTNode))))exit(0);
		T->data = a;
		CreateBiTree(T->lchid);
		CreateBiTree(T->rchid);
	}
}

//先序遍历
void PreOrderTraverse(BiTree& T, SqStack& S) {
	BiTree t = T;//用遍历结点t来遍历
	while (t || S.top != 0) {
		while (t) {//遍历左结点
			printf("%c", t->data);//在寻找下一个左结点前先访问数据即为先序
			Push(S, t);
			t = t->lchid;
		}
		if (S.top != 0) {//左节点遍历完后取栈顶遍历右节点
			t = Pop(S);
			t = t->rchid;
		}
	}
}

//中序遍历
void InOrderTraverse(BiTree& T, SqStack& S) {
	BiTree t = T;//用遍历结点t来遍历
	while (t || S.top != 0) {
		while (t) {//遍历左结点
			Push(S, t);
			t = t->lchid;
		}
		if (S.top != 0) {//左节点遍历完后取栈顶遍历右节点
			t = Pop(S);
			printf("%c", t->data);//在寻找下一个右结点前先访问数据即为中序
			t = t->rchid;
		}
	}
}

//后序遍历(根节点被第二次遍历时才访问)
void PostOrderTraverse(BiTree& T, SqStack& S) {
	BiTree t = T;//用遍历结点t来遍历
	while (t || S.top != 0) {//遍历左结点
		while (t) {
			t->cnt = 1;//主要用于记录根节点已被遍历一次
			Push(S, t);
			t = t->lchid;
		}
		if (S.top != 0) {//左节点遍历完后取栈顶遍历右节点
			t = Pop(S);
			if (t->cnt == 1) {//根节点只被遍历一次
				t->cnt++;//次数增加
				Push(S, t);//重新存入根节点
				t = t->rchid;//向右继续遍历
			}
			else if (t->cnt == 2) {//根节点被遍历两次即可以访问
				printf("%c", t->data);
				t = NULL;//置空t以免再继续遍历左节点进入死循环
			}
		}
	}
}

int main() {
	BiTree T;
	printf("请输入二叉树数据:\n");
	CreateBiTree(T);
	SqStack S;
	InitStack(S);
	printf("先序遍历结果为:\n");
	PreOrderTraverse(T, S);
	printf("\n中序遍历结果为:\n");
	InOrderTraverse(T, S);
	printf("\n后序遍历结果为:\n");
	PostOrderTraverse(T, S);
}

运行结果如下:

第二种思路:(后序)建立二叉树类型的模拟栈,用两个指针一个用于遍历一个用于记录遍历指针的直接前驱,判断遍历指针所指根结点有有右子女且未访问过时,不将根节点出栈,第二次判断遍历指针所指根结点有有右子女且已访问过后则访问当前根节点

本思路对栈的基本操作完整定义写法要求较低,只要理解栈的工作原理即可,且代码相对较短,但理解相对困难

代码如下:(我先序中序后序都写了)

#include<stdio.h>
#include<stdlib.h>

#define STACK_INIT_SIZE 100
typedef char TElemType;
typedef struct BiTNode {
	TElemType data;
	struct BiTNode* lchid, * rchid;
}BiTNode, * BiTree;

void CreateBiTree(BiTree& T) {
	TElemType a;
	TElemType temp;
	scanf("%c", &a);
	temp = getchar();
	if (a == '.')
		T = NULL;
	else {
		if (!(T = (BiTNode*)malloc(sizeof(BiTNode))))exit(0);
		T->data = a;
		CreateBiTree(T->lchid);
		CreateBiTree(T->rchid);
	}
}

//先序遍历
void PreOrderTraverse(BiTree T) {
	BiTree S[STACK_INIT_SIZE];
	BiTree t = T; //t为遍历指针
	int top = -1; //top记录当前栈顶结点下标
	do {
		while (t != NULL) { //遍历左子女结点
			printf("%c", t->data); //在寻找下一个左结点前先访问数据即为先序
			S[++top] = t; //进栈
			t = t->lchid;
		}
		if (top > -1) {
			t = S[top--]; //退栈
			t = t->rchid;
		}
	} while (t != NULL || top > -1);
}

//中序遍历
void InOrderTraverse(BiTree T) {
	BiTree S[STACK_INIT_SIZE];
	BiTree t = T;
	int top = -1;
	do {
		while (t != NULL) {
			S[++top] = t;
			t = t->lchid;
		}
		if (top > -1) {
			t = S[top--];
			printf("%c", t->data); //在寻找下一个右结点前先访问数据即为中序
			t = t->rchid;
		}
	} while (t != NULL || top > -1);
}

//后序遍历
void PostOrderTraverse(BiTree T) {
	BiTree S[STACK_INIT_SIZE];
	BiTree t = T, pret = NULL; //t为遍历指针,pret为其前驱指针
	int top = -1;
	do {
		while (t != NULL) {
			S[++top] = t;
			t = t->lchid;
		}
		if (top > -1) {
			t = S[top];
			if (t->rchid != NULL && t->rchid != pret)//t有右子女且未访问过则不出栈
				t = t->rchid;
			else {
				printf("%c", t->data);
				pret = t; //记录当前t
				t = NULL; //置空,待下次从栈中取得下一结点
				top--; //出栈
			}
		}
	} while (t != NULL || top > -1);
}

int main() {
	BiTree T;
	printf("请输入二叉树数据:\n");
	CreateBiTree(T);
	printf("先序遍历结果为:\n");
	PreOrderTraverse(T);
	printf("\n中序遍历结果为:\n");
	InOrderTraverse(T);
	printf("\n后序遍历结果为:\n");
	PostOrderTraverse(T);
}

 运行结果如下:


 本次记录就到这~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值