/*二叉树的遍历之非递归实现*/
/*非递归实现采用栈去模拟实现*/
//参考代码http://blog.csdn.net/ns_code/article/details/12977901
节点访问
1 void visit(BTNode*b)
2 {
3 //输出格式依赖于elementType
4 printf("%c",b->data);
5 }
先序遍历
根据先序遍历的顺序,先访问根节点,再访问左子树,后访问右子树,而对于每个子树来说,
又按照同样的访问顺序进行遍历。非递归的实现思路如下:
对于任一节点P,
1)输出节点P,然后将其入栈,再看P的左孩子是否为空;
2)若P的左孩子不为空,则置P的左孩子为当前节点,重复1)的操作;
3)若P的左孩子为空,则将栈顶节点出栈,但不输出,并将出栈节点的右孩子置为当前节点,
看其是否为空;
4)若不为空,则循环至1)操作;
5)如果为空,则继续出栈,但不输出,同时将出栈节点的右孩子置为当前节点,看其是否
为空,重复4)和5)操作;
6)直到当前节点P为NULL并且栈空,遍历结束。
void PreOrder(BTree bt)
{
PSTACK stack=NULL;
stack=CreateStack(); //创建一个空栈
elementType node_pop; //用来保存出栈节点
elementType pCur=bt; //用来保存当前访问节点的指针
//直到当前节点pCur为NULL且栈空,循环结束
while(pCur||!IsEmpty(stack))
{
//从根节点开始,输出当前节点,并将其入栈
visit(pCur);
PushStack(pCur,stack);
//当左孩子为NULL,且栈不空,则将栈顶节点出栈
pCur=pCur->lchild;
while(!pCur&&!IsEmpty(stack))
{
//节点出栈,判断右孩子是否为空
node_pop=TopAndPop(stack);
pCur=node_pop->rchild;
//右孩子空,跳回此级循环头部继续出栈
//右孩子非空,跳回上级循环头部
}
//当左孩子不空 ,跳回开头
}
DisposeStack(stack);
}
中序遍历的非递归实现
根据中序遍历的顺序,先访问左子树,再访问根节点,后访问右子树,而对于
每个子树来说,又按照同样的访问顺序进行遍历,上图的中序遍历顺序为:
DBEAFC。非递归的实现思路如下:
对于任一节点P,
1)若P的左孩子不为空,则将P入栈并将P的左孩子置为当前节点,然后再对
当前节点进行相同的处理;
2)若P的左孩子为空,则输出P节点,而后将P的右孩子置为当前节点,看其
是否为空;
3)若不为空,则重复1)和2)的操作;
4)若为空,则执行出栈操作,输出栈顶节点,并将出栈的节点的右孩子置为
当前节点,看起是否为空,重复3)和4)的操作;
5)直到当前节点P为NULL并且栈为空,则遍历结束。
下面是自己写的,有些臃肿
void InOrder(BTree bt)
{
PSTACK s=CreateStack(); //创建一个空栈
BTree p=bt; //定义指向当前访问节点的指针
elementType node_pop; //用来保存出栈节点
while(p!=NULL||!IsEmpty(s))
//当前节点p==!NULL或栈非空时,循环1
{
//若左孩子不为空
if(p->lchild!=NULL)
{
//当前节点P入栈,左孩子置为当前节点,跳回循环1头部
PushStack(p,s);
p=p->lchild;
}
//若左孩子为空
else
{
//输出p节点
visit(p);
//判断右孩子,循环2
while(p->rchild==NULL)
{
//若右孩子为空
if(!IsEmpty(s))
{
//判断栈是否为空
//栈非空,执行出栈操作,输出栈顶节点,跳回此级循环2头部
p=TopAndPop(s);
visit(p);
}
else
//栈空,程序结束
{
return;
}
}
//若右孩子不为空
//置右孩子为当前节点,跳回上级循环1头部
if(p->rchild!=NULL)
p=p->rchild;
}
}
}
下面是参考前辈的代码http://blog.csdn.net/ns_code/article/details/12977901,接驳自己的接口
void InOrder(BTree pTree)
{
PSTACK stack = CreateStack(); //创建一个空栈
BTree node_pop; //用来保存出栈节点
BTree pCur = pTree; //定义指向当前访问的节点的指针
//直到当前节点pCur为NULL且栈空时,循环结束
while(pCur ||!IsEmpty(stack))
{
if(pCur->lchild)
{
//如果pCur的左孩子不为空,则将其入栈,并置其左孩子为当前节点
PushStack(pCur,stack);
pCur = pCur->lchild;
}
else
{
//如果pCur的左孩子为空,则输出pCur节点,并将其右孩子设为当前节点,看其是否为空
visit(pCur);
pCur = pCur->rchild;
//如果为空,且栈不空,则将栈顶节点出栈,并输出该节点,
//同时将它的右孩子设为当前节点,继续判断,直到当前节点不为空
while(!pCur && !IsEmpty(stack))
{
pCur = TopAndPop(stack);
visit(pCur);
pCur = pCur->rchild;
}
}
}
}
前辈写的,明显精炼许多。需要多多看齐呀。
后序遍历的非递归实现
根据后序遍历的顺序,先访问左子树,再访问右子树,后访问根节点,
而对于每个子树来说,又按照同样的访问顺序进行遍历。后序遍历的
非递归的实现相对来说要难一些,要保证根节点在左子树和右子树被
访问后才能访问,思路如下:
对于任一节点P,
1)先将节点P入栈;
2)若P不存在左孩子和右孩子,或者P存在左孩子或右孩子,但左右
孩子已经被输出,则可以直接输出节点P,并将其出栈,将出栈节点P
标记为上一个输出的节点,再将此时的栈顶结点设为当前节点;
3)若不满足2)中的条件,则将P的右孩子和左孩子依次入栈,当前
节点重新置为栈顶结点,之后重复操作2);
4)直到栈空,遍历结束。
自己写的弯弯绕绕
void PostOrder(BTree bt)
{
PSTACK stack=CreateStack(); //创建一个空栈
BTree pCur=NULL; //当前工作节点指针
BTree pPre=NULL; //上一个完成访问的节点指针
//根节点为当前节点
pCur=bt;
//若当前节点不空,循环1
while(pCur)
{
//debug
//PrintStack(stack);
//printf("\n");
//当前节点入栈
PushStack(pCur,stack);
//判断右孩子
//右孩子被访问
if(pPre!=NULL&&pCur->rchild==pPre)
{
//栈顶节点(其实就是当前节点)出栈,visit当前节点,并置为pPre,再次将栈顶元素出栈(栈空时出栈结果是NULL),置为当前节点,跳回循环1头部
PopStack(stack);
visit(pCur);
pPre=pCur;
pCur=TopAndPop(stack);
}
else if(pCur->rchild==NULL)
{
//没有右孩子
//判断左孩子
if(pCur->lchild==NULL||(pPre!=NULL&&pCur->lchild==pPre))
{
//没有左孩子或左孩子被访问过
//栈顶节点出栈,visit当前节点,置为pPre,栈顶元素出栈,置为当前节点,跳回循环1头部
PopStack(stack);
visit(pCur);
pPre=pCur;
pCur=TopAndPop(stack);
}
else
{
//左孩子没被访问过
//左孩子置为当前节点 ,跳回循环1头部
pCur=pCur->lchild;
}
}
else
{
//右孩子没被访问过
//判断左孩子
if(pCur->lchild==NULL||(pPre!=NULL&&pCur->lchild==pPre))
{
//左孩子被访问过 或没有左孩子
//右孩子置为当前节点,跳回循环1头部
pCur=pCur->rchild;
}
else
{
//左孩子没被访问过
//右孩子入栈,左孩子置为当前节点,跳回循环1头部
PushStack(pCur->rchild,stack);
pCur=pCur->lchild;
}
}
}
}
下面是参考前辈的代码http://blog.csdn.net/ns_code/article/details/12977901,接驳自己的接口
void PostOrder(BTree bt)
{
PSTACK stack=CreateStack(); //建立一个空栈
BTree pCur=NULL; //当前访问节点的指针
BTree pPre=NULL; //上一个访问节点的指针
//根节点入栈
PushStack(bt,stack);
//当栈非空时,循环1
while(!IsEmpty(stack))
{
//当前指针置为栈顶节点
pCur=TopStack(stack);
//如果当前节点pCur不存在左孩子和右孩子,或者存在左孩子和右孩子,但左右孩子已经被输出
if((pCur->lchild==NULL&&pCur->rchild==NULL)||(pPre!=NULL&&(pCur->lchild==pPre||pCur->rchild==pPre)))
{
//直接输出栈顶节点,并将其出栈,标记为上一个输出的节点pPre,
pPre=TopAndPop(stack);
visit(pPre);
}
else
{
//否则
//(如果存在右孩子)pCur的右孩子入栈,(如果存在左孩子)然后pCur的左孩子入栈
if(pCur->rchild!=NULL)
PushStack(pCur->rchild,stack);
if(pCur->lchild!=NULL)
PushStack(pCur->lchild,stack);
}
}
}
来源:https://www.cnblogs.com/w784319947/p/6429755.html