二叉树非递归遍历的实现

◇◆丶佛笑我妖孽 提交于 2020-01-21 07:30:58

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

    }
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!