#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define MAXSIZE 100
#define NULL 0
typedef char TElemtype;
typedef struct BiTNode
{
TElemtype data;
struct BiTNode *lchild,*rchild; //左右孩子指针
}BiTNode, *BiTree;
//先序创建二叉树链表
int CreateBiTree(BiTNode*&T) //之所以要用引用,是因为该函数中指针T会改变,而这种改变必须带回到主函数中
{ //按先序次序输入二叉树中结点的值(一个字符),#字符表示空树
char ch;
scanf("%c",&ch);
getchar();
if(ch=='#') T=NULL;
else
{
T=(BiTNode *)malloc(sizeof(BiTNode));
if(!T) return 0;
else
{
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
}
return 1;
}
//按照层次非递归创建二叉树链表
int CreateBiTree2(BiTNode*&T)
{
//采用顺序队列存放
BiTNode *s[MAXSIZE];
int front=-1,rear=0; //队列的队首和队尾
//创建根结点
BiTNode *p;
T=(BiTNode *)malloc(sizeof(BiTNode));
if(!T) return 0;
char ch=getchar();
T->data=ch;
//将根结点入队
s[rear]=T; //这里没有采用循环队列,数据从下标0开始存储,当front=rear时,表明队列为空
while(rear!=front)
{
//出队一个元素
p=s[++front];
p->lchild=NULL;
p->rchild=NULL;
//输入其2个儿子,其中注意表示空结点的特殊字符
char ldata=getchar();
char rdata=getchar();
if(ldata!='#') //左孩子入队
{
if(!(p->lchild=(BiTNode *)malloc(sizeof(BiTNode)))) return 0;
p->lchild->data=ldata;
s[++rear]=p->lchild;
}
if(rdata!='#') //右孩子入队
{
if(!(p->rchild=(BiTNode *)malloc(sizeof(BiTNode)))) return 0;
p->rchild->data=rdata;
s[++rear]=p->rchild;
}
}
}
//________________________________________________________
//按层次遍历二叉树链表,和按层次创建二叉树类似
void LeverTraverse(BiTNode *T)
{
//采用顺序队列存放
BiTNode *s[MAXSIZE];
BiTNode *p;
int front=-1,rear=0; //队列的队首和队尾
//将根结点入队
s[rear]=T; //这里没有采用循环队列,数据从下标0开始存储,当front=rear时,表明队列为空
while(rear!=front)
{
//出队一个元素并输出
p=s[++front];
printf("%c",p->data);
if(p->lchild) //左孩子入队
{
s[++rear]=p->lchild;
}
if(p->rchild) //右孩子入队
{
s[++rear]=p->rchild;
}
}
}
//按层次遍历二叉树链表,和按层次创建二叉树类似
void LeverTraverse2(BiTNode *T)
{
//采用顺序队列存放
BiTNode *s[MAXSIZE];
BiTNode *p;
int front=-1,rear=0; //队列的队首和队尾
//将根结点入队
printf("%c",T->data);
s[rear]=T; //这里没有采用循环队列,数据从下标0开始存储,当front=rear时,表明队列为空
while(rear!=front)
{
//出队一个元素并输出
p=s[++front];
if(p->lchild) //左孩子入队
{
printf("%c",p->lchild->data);
s[++rear]=p->lchild;
}
if(p->rchild) //右孩子入队
{
printf("%c",p->rchild->data);
s[++rear]=p->rchild;
}
}
}
//_______________________________________________________
//先序递归遍历二叉链表
void PreOrderTraverse(BiTNode *T)
{
if(T)
{
printf("%c",T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
//先序非递归遍历二叉树
void NPreOrderTraverse(BiTNode *T)
{
//思路:模仿递归遍历的路径,采用栈来模拟,先根,再左右
BiTNode *s[MAXSIZE];
BiTNode *p=T;
int top=-1;
while(p||top!=-1)
{
while(p) //很显然这个while可以用if替代,循环采用外层的循环
{//此时已输出从根到最左边的结点,并都已入栈
printf("%c",p->data);
s[++top]=p;
p=p->lchild;
}
//将栈中左孩子依次出栈
/*if(top!=-1)*/ p=s[top--];
p=p->rchild;
}
}
//还有更直接的思维,就是把访问根结点,然后右结点入栈,最后左结点入栈
//先序非递归遍历二叉树2
void NPreOrderTraverse2(BiTNode *T)
{
//思路:模仿递归遍历的路径,采用栈来模拟,先根,再左右
BiTNode *s[MAXSIZE];
BiTNode *p=T;
int top=-1;
while(p||top!=-1)
{
if(p) //很显然这个while可以用if替代,循环采用外层的循环
{ //此时已输出从根到最左边的结点,并都已入栈
printf("%c",p->data);
s[++top]=p;
p=p->lchild;
}
else
{
//将栈中左孩子依次出栈
/*if(top!=-1)*/ p=s[top--];
p=p->rchild;
}
}
}
//________________________________________________________________________
//中序递归遍历二叉链表
void InOrderTraverse(BiTNode *T)
{
if(T)
{
InOrderTraverse(T->lchild);
printf("%c",T->data);
InOrderTraverse(T->rchild);
}
}
//中序非递归遍历二叉树
void NInOrderTraverse(BiTNode *T)
{
//思路:模仿递归遍历的路径,采用栈来模拟,先左,再根,最后右
BiTNode *s[MAXSIZE];
BiTNode *p=T;
int top=-1;
while(p||top!=-1)
{
while(p) //很显然这个while可以用if替代,循环采用外层的循环
{//此时将根到最左边入栈,但不输出
s[++top]=p;
p=p->lchild;
}
//将栈中左孩子依次出栈,并输出
/*if(top!=-1)*/ p=s[top--];
printf("%c",p->data);
p=p->rchild;
}
}
//中序非递归遍历二叉树2
void NInOrderTraverse2(BiTNode *T)
{
//思路:模仿递归遍历的路径,采用栈来模拟,先左,再根,最后右
BiTNode *s[MAXSIZE];
BiTNode *p=T;
int top=-1;
while(p||top!=-1)
{
if(p) //很显然这个while可以用if替代,循环采用外层的循环
{//此时将根到最左边入栈,但不输出
s[++top]=p;
p=p->lchild;
}
else
{
//将栈中左孩子依次出栈,并输出
/*if(top!=-1)*/ p=s[top--];
printf("%c",p->data);
p=p->rchild;
}
}
}
//__________________________________________________________________________
//后序递归遍历二叉链表
void PostOrderTraverse(BiTNode *T)
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c",T->data);
}
}
//后序非递归遍历二叉树
void NPostOrderTraverse(BiTNode *T)
{
//思路:模仿递归遍历的路径,采用栈来模拟,先左右,再根
//这里没有采用辅助数组,只是应用了当某结点的前一个被访问结点是其右孩子,或其右孩子是NULL,则输出
BiTNode *s[MAXSIZE];
BiTNode *p=T,*pre=NULL; //pre指示当前结点的前一结点
int top=-1;
while(p||top!=-1)
{
while(p)
{
s[++top]=p;
p=p->lchild;
} //一直到二叉树最左边结点
p=s[top--];
if(p->rchild==NULL||p->rchild==pre) //当p->rchild刚好是上一个已访问的结点时,访问此结点
{
printf("%c",p->data);
pre=p;
p=NULL; //让它跳过while(p),否则进入死循环
}
else
{
s[++top]=p;//p必须重新入栈,或者前面的p=s[top--]改为p=s[top]也可;
//所以,中序或后序的非递归算法可以采用比对入栈的次数来实现
p=p->rchild;//让右结点进栈
}
}
}
//后序非递归遍历二叉树2
void NPostOrderTraverse2(BiTNode *T)
{
//思路:模仿递归遍历的路径,采用栈来模拟,先左右,再根
//这里采用辅助数组
BiTNode *s[MAXSIZE];
int tag[MAXSIZE]; //设计一个辅助数组,指示其右孩子是否被访问了
BiTNode *p=T;
int top=-1;
while(p||top!=-1)
{
while(p)
{
++top;
s[top]=p;
tag[top]=0; //设置右孩子没访问
p=p->lchild;
}
p=s[top];
if(p->rchild==NULL||tag[top]==1) //这里可以用内循环,只要满足这个条件就出栈输出
{
printf("%c",p->data);
top--;
p=NULL; //让它跳过while(p),否则进入死循环
}
else
{
tag[top]=1;
p=s[top]->rchild;
}
}
/* 参考代码
void NPostOrderTraverse3(BiTree *T)
{
BiTree p;
Stack *st;
initstack(st);
p=T;
int Tag[20]; //栈,用于标识从左(0)或右(1)返回
while (p!=NULL || !isempty(st))
{
while (p!=NULL)
{
push(st,p);
Tag[st->top]=0;
p=p->lchild;
}
while (!isempty(st)&&Tag[st->top]==1)
{
p=pop(st);
cout<<p->data<<" ";
//这里是不是少了p=NULL?,不需要,因为运行此处while后转入下面的if,那么由p=gettop(st)来改变p
}
if (!isempty(st))
{
Tag[st->top]=1; //设置标记右子树已经访问,无论右子节点是否为空或一个实体
p=gettop(st);
p=p->rchild;
}
else break;
}*/
//_____________________________________________________________________
}
//谭浩强数据结构辅导书里面的后序非递归遍历挺有意思的
//附注:愈勇编写的二叉树中序、后序非递归遍历,采用判断结点到底是第几次入栈,
//即:先让根结点入栈,出栈,若左孩子非空,则让根结点入栈,再让左孩子入栈等等;若非叶子结点入栈次数等于2或3就输出
typedef struct BiTNode2
{
TElemtype data;
struct BiTNode2 *lchild,*rchild; //左右孩子指针
int num;
}BiTNode2, *BiTree2;
//先序创建二叉树链表
int CreateBiTree3(BiTNode2*&T) //之所以要用引用,是因为该函数中指针T会改变,而这种改变必须带回到主函数中
{ //按先序次序输入二叉树中结点的值(一个字符),#字符表示空树
char ch;
scanf("%c",&ch);
getchar();
if(ch=='#') T=NULL;
else
{
T=(BiTNode2 *)malloc(sizeof(BiTNode2));
if(!T) return 0;
else
{
T->data=ch;
CreateBiTree3(T->lchild);
CreateBiTree3(T->rchild);
}
}
return 1;
}
void NPostOrderTraverse4(BiTNode2 *T)
{
BiTNode2 *s[MAXSIZE];
BiTNode2 *p=T;
int top=-1;
while(p||top!=-1)
{
while(p)
{
++top;
p->num=0;
s[top]=p;
p=p->lchild;
}
p=s[top--]; //表示第一次出栈出栈
p->num++; //表示此时出栈次数为1
if(p->num==2||p->rchild==NULL)
{
printf("%c",p->data);
p=NULL;
}
else if(p->rchild)
{
s[++top]=p; //p再次入栈
p=p->rchild;
}
}
}
void main()
{
BiTNode2*T=NULL;
printf("请先序创建二叉树链表\n");
CreateBiTree3(T);
//printf("\n请先序递归遍历二叉链表\n");
//PreOrderTraverse(T);
//printf("\n请先序非递归遍历二叉链表\n");
//NPreOrderTraverse2(T);
//printf("请按层次创建二叉树链表\n");
//CreateBiTree2(T);
//printf("\n请按层次遍历二叉链表\n");
//LeverTraverse2(T);
//printf("\n请中序递归遍历二叉链表\n");
//InOrderTraverse(T);
//printf("\n请中序非递归遍历二叉链表\n");
//NInOrderTraverse2(T);
//printf("\n请后序递归遍历二叉链表\n");
//PostOrderTraverse(T);
printf("\n请后序非递归遍历二叉链表\n");
NPostOrderTraverse4(T);
getchar();
}