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);
}
运行结果如下:
本次记录就到这~