二叉树的特点是每个结点至多只有两棵子树,它是一种很重要的数据结构,从树的特点我们可以利用递归很容易的实现它的创建以及遍历操作,上一篇已经用递归的方法实现了二叉树的先序、中序和后序的遍历,下面的代码是二叉树的非递归遍历的实现,三种遍历方式都给出了两种实现方法(注释掉的即为第二种实现方法),注释部分已经讲原理写出来了,由于自己语言组织能力不是很好,原理就是从网上找来的,我自己是通过这些原理来实现的遍历二叉树,希望也能给看到代码的人同样帮助。
/*
*@2012-12-14
*二叉树的非递归(先序、中序、后序)遍历
*/
#include<iostream>
using namespace std;
typedef char TElemType; //二叉树数据元素的类型
typedef struct BitreeNode
{
TElemType TItem;
struct BitreeNode *lchild;
struct BitreeNode *rchild;
}BitreeNode,*Bitree;
typedef struct SNode
{
Bitree SItem;
struct SNode *next;
}SNode , * LinkStack;
//初始化二叉树
int InitBitree(Bitree &T)
{
T=(Bitree)malloc(sizeof(BitreeNode));
if(!T)
return 0;
T->TItem='#';
T->lchild=NULL;
T->rchild=NULL;
return 1;
}
//初始化栈
int InitStack(LinkStack &S)
{
S=(LinkStack)malloc(sizeof(SNode)); //通过malloc函数分配空间
if (!S)
return 0; //如果分配失败,则返回0
S->next=NULL;
return 1;
}
//判断栈是否为空
int StackEmpty(LinkStack S)
{
if (S!=NULL) //判断栈是否存在
{
if (S->next==NULL)
{
return 1;
}
}
return 0;
}
//创建二叉树
int CreateBitree(Bitree &T)
{
TElemType ch;
ch=getchar();//测试字符串abc##de#g##f###
if(ch=='#')
T=NULL;
else
{
T=(Bitree)malloc(sizeof(BitreeNode));
if(!T)
return 0;
else
{
T->TItem=ch;
CreateBitree(T->lchild);
CreateBitree(T->rchild);
}
}
return 1;
}
//获取栈顶元素
int GetTop(LinkStack S,Bitree &e)
{
LinkStack q=S;
if (S!=NULL) //判断栈是否存在
{
if (q->next!=NULL)//判断栈是否为空
{
while (q->next!=NULL)
{
q=q->next;
}
e=q->SItem;
return 1;
}
}
return 0; //如果不能得到数据元素,则返回0(false)
}
//压栈函数
int Push(LinkStack &S,Bitree e)
{
LinkStack q=S;
LinkStack m=(LinkStack)malloc(sizeof(SNode)); //通过malloc函数分配空间
if (S!=NULL)
{
while (q->next!=NULL)
{
q=q->next;
}
m->SItem=e;
m->next=NULL;
q->next=m;
}
return 0;
}
//出栈函数
int Pop(LinkStack &S,Bitree &e)
{
LinkStack q=S;
if (S!=NULL)
{
if (q->next!=NULL) //若栈不是空的
{
while (q->next->next!=NULL)
{
q=q->next;
}
e=q->next->SItem;
q->next=NULL;
return 1;
}
}
return 0;
}
//遍历访问函数
int Visit(TElemType e)
{
if(e!=NULL)
{
cout<<e<<" ";
return 1;
}else
return 0;
}
/*先序遍历二叉树根->左->右;
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);
若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
*/
int PreOrederTraverse(Bitree &T,int(*Visit)(TElemType))
{
/* LinkStack S;
Bitree p=T;
InitStack(S);
Push(S,T);
while (p || !StackEmpty(S))
{
while (p!=NULL)
{
Visit(p->TItem);
Push(S,p);
p=p->lchild;
}
if(!StackEmpty(S))
{
GetTop(S,p);
Pop(S,p);
p=p->rchild;
}
}
*/
LinkStack S;
Bitree p=T;
InitStack(S);
Push(S,T);
while (!StackEmpty(S))
{
while (GetTop(S,p) && p)
{
if(!Visit(p->TItem))
return 0;
Push(S,p->lchild);//向左走到尽头
}
Pop(S,p);//空指针退栈
if(!StackEmpty(S)){//访问节点,向右一步
Pop(S,p);
Push(S,p->rchild);
}
}
return 0;
}
/*
*中遍历二叉树:左->根->右
1)若其左孩子不为空,则将P入栈并将P的左孩子置为当前的P,然后对当前结点P再进行相同的处理;
2)若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的P置为栈顶结点的右孩子;
3)直到P为NULL并且栈为空则遍历结束
*/
int InOrderTraverse(Bitree &T,int(*Visit)(TElemType))
{
/* LinkStack S;
Bitree p=T;
InitStack(S);
Push(S,T);//根指针进栈
while (p || !StackEmpty(S))
{
if(p)
{
Push(S,p);
p=p->lchild;//根指针进栈,遍历左子树
}
else//根指针退栈,访问根结点,遍历右子树
{
Pop(S,p);
if(!Visit(p->TItem))
return 0;
p=p->rchild;
}
}*/
LinkStack S;
Bitree p=T;
InitStack(S);
Push(S,T);//根指针进栈
while (!StackEmpty(S))
{
while (GetTop(S,p) && p)
{
Push(S,p->lchild);//向左走到尽头
}
Pop(S,p);//空指针退栈
if(!StackEmpty(S)){//访问节点,向右一步
Pop(S,p);
if(!Visit(p->TItem))
return 0;
Push(S,p->rchild);
}
}
return 1;
}
/*
*后序遍历二叉树:左->右->根
1)对于任一结点P,先将其入栈。
2)如果P不存在左孩子和右孩子,或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则可以直接访问该结点。
3)若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问。
左孩子和右孩子都在根结点前面被访问。
*/
int PostOrderTraverse(Bitree &T,int(*Visit)(TElemType))
{
/* Bitree q=T;
LinkStack S;
InitStack(S);
while (T || !StackEmpty(S))
{
if (T)
{
Push(S, T);
T=T->lchild;
}
else
{
GetTop(S, T);
if (T->rchild==NULL || T->rchild==q)
{
Visit(T->TItem);
Pop(S, T);
q=T;
T=NULL;
}
else
{
T=T->rchild;
}
}
}*/
LinkStack S;
Bitree cur;//当前结点
Bitree pre=NULL;//前一次访问的结点
InitStack(S);
Push(S,T);//根指针进栈
while(!StackEmpty(S))
{
GetTop(S,cur);
if((cur->lchild==NULL&&cur->rchild==NULL)||
(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild)))
{//如果当前结点没有孩子结点或者孩子节点都已被访问过
Visit(cur->TItem);
Pop(S,cur);
pre=cur;
}
else//将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问
{
if(cur->rchild!=NULL)
Push(S,cur->rchild);
if(cur->lchild!=NULL)
Push(S,cur->lchild);
}
}
return 0;
}
int main()
{
Bitree T;
InitBitree(T);
CreateBitree(T);
cout<<"先序遍历:";
PreOrederTraverse(T,Visit);
cout<<endl;
cout<<"中序遍历:";
InOrderTraverse(T,Visit);
cout<<endl;
cout<<"后序遍历:";
PostOrderTraverse(T,Visit);
cout<<endl;
return 0;
}