/*二叉树的遍历之非递归实现*/
/*非递归实现采用栈去模拟实现*/
//参考代码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