二叉树的非递归遍历要借助栈,栈起到的作用是保护现场?或者说记录来的路程,因为没有线索指向你当前结点的前驱,当当前结点处理完要返回上几层中的结点(来路)的时候就没有办法,因此需要用栈来记录来的过程,需要的时候用GetTop()或者直接Pop()函数就可以找到来的路。
1.前序
void PreOrder(BiTree T){
InitStack(S);
BiTree p=T;
while(!=StackEmpty(S)){
if(p){
visit(p);
Push(S,p);
p=p->lchild;
}
else{
Pop(S,p);
p=p->rchild;
}
}
}
2.中序
void InOrder(BiTree T){
InitStack(S);BiTree p;//光标p
while(p||!IsEmpty(S)){
if(p){ //该if检查当前结点是否有左子(是否已经是最又)
Push(S,p);//无论怎样先将当前结点入栈
p=p->lchild;//在此层提前进入下一个结点形成循环
}
else{//如果进入到else说明当前结点已经无左子,中序下则可以回到上一个现场,将该结点访问出栈
Pop(S,p);visit(p);
p=p->rchild;//访问完后接着检查右子,若有右子则新开一树进入到if(p);若没有右子则退栈回到上上个现场访问某个祖先
}
2.后序
void LostOrder(BiTree T){
InitStack(S);BiTree p,r;
p=T;
r=NULL;
while(p||!IsEmpty(S)){//与中序相同的操作检查是否有左子
if(p){
Push(S,p);
p=p->lchild;
}
else{//能进到else语句已经说明上一结点的左子不存在,直接开始检查右子
GetTop(S,p);//if(p)结束时p还固定在不存在的左子NULL上
if(p->rchild&&p->rchild!=r){//判断当前结点是否有右子且未被标记
p=p->rchild;//有则进入右子
Push(S,p);//▲注意每一个新结点都入栈
p=p->lchild;//以该右子为根开新树从if(p)开始重复一轮
}
else{//上一结点没有右子(或右子已经检索过)则进入此条,左右已经检查完,可以访问这个结点
Pop(S,p);
visit(p);
r=p;//能进到这一else的结点肯定是某个祖先右子孙,若不标记同时在if中不加r判据,就会导致返回祖先时检查右子又发现有结点,就重复进入该结点
p=NULL;//现在p还插在刚出栈的结点上,不置零的化一到开头if(p)又要重复,因此置零把if跳过,然后取栈顶
}
}//else1
}//while
}//LostOrder