【算法】非递归不用栈的二叉树遍历算法伪代码

树的遍历,尤其是二叉树的遍历算法是常见并且非常重要的,关于这个问题的讨论网上已经有很多,并且很多教材也做了分析,从递归实现,到非递归用栈来实现,以及非递 归不用栈来实现,最后一种被认为是繁琐的,特别具体实现时要考虑不少细节,下面是 我整理的比较容易写出来且容易记忆的一种写法,算是抛砖引玉吧。

不能使用栈的话,可以通过向节点中添加指向父亲的指针域,用来达到回溯的效果,并且 用一个变量来记录当前节点的访问状态,分为如下三种:

左子树未遍历;
左子树已遍历(包括左子树为空);
右子树已遍历(右子树为空)。

在下面的伪代码中我是这样考虑的:
一个节点有一个域指出来它是否有左子树,一是有左子树,二是没有左子树,对这两种情 况分别处理上面提到的三种访问状态,直到迭代结束,这样我们就保证算法是正确的。而 且是容易记忆的,实际上你将会发现它们是很容易写出来的,只要你心中牢记上面考虑的 解决思路。

因为很多书上都把中序遍历作为习题,甚至有些面试题上也是这样,所以我只注释了中序, 实际上这三种方法只有访问节点的地方不一样,其他是一摸一样的。伪码的有些地方使用 了《算法导论》中的风格,如left[root]指节点root的左孩子等,大体上应该很容易阅读 的。

enum TRAVESAL_STATE
{
    LEFT_NOT_TRAVERS ; //左子树未遍历
    LEFT_TRAVERSED ; //左子树已遍历(包括左子树为空)
    RIGHT_TRAVERSED ; //右子树已遍历(右子树为空)
}

in-order(中序)

/******************* in-order start *******************************/
if (root  == NIL )
    结束 ;
//找到遍历的结束点end.
while (right [root ]  ! = NIL )
{
    end  = right [root ] ;
}
// 记录初始状态
state  = LEFT_NOT_TRAVERS ;
//这里有一个比较隐蔽的地方需要注意,不能只靠 (root != end) 判断是否
//遍历结束,如果end有左子树的话它和它的子树就遍历不了了。我们用一个变
//量来记录是否已经遍历了end,如果遍历了end那么它的子树肯定已经遍历
//了,这是中序遍历的性质。当然可以写成不需要设置变量的形式,但代码看
//起来不一定舒服。对于前序后序也有这个问题.
real_end  =  false ;
while (  !real_end  )
{
     //左子树不为空的情况
     if (left [root ]  ! = NIL )
     {
         switch (state )
         {
             //左子树没有遍历的话去处理左子树
             case LEFT_NOT_TRAVERS :
                root  = left [root ] ;
                state  = LEFT_NOT_TRAVERS ;
                 break ;

             //左子树已经处理完了,则访问该节点,如果没有右子树,则设置访问状态为
             //右子树已遍历,见上面概述,否则去处理右子树。
             case LEFT_TRAVERSED :
                 /****************/
                访问root;
                 if ( root  = end  )
                 {
                    real_end  =  true ;
                     break ;
                 }
                 /****************/
                 if  (right [root ]  == NIL )
                 {
                    state  = RIGHT_TRAVERSED ;
                 }
                 else
                 {
                    root  = right [root ] ;
                    state  = LEFT_NOT_TRAVERS ;
                 }
                 break ;

             //右子树处理完了的话,向上回溯
             case RIGHT_TRAVERSED :
                 if ( right [parent [root ] ]  ! = root  )
                    state  = LEFT_TRAVERSED ;
                root  = parent [root ] ;
                 break ;
         }
     }
     else
     {
         switch (state )
         {
             //设置访问状态
             case LEFT_NOT_TRAVERS ;
                state  = LEFT_TRAVERSED ;
                 break ;

             //左子树已经处理完了,则访问该节点,如果没有右子树,则设置访问状态为
             //右子树已遍历,见上面概述,否则去处理右子树。
             case LEFT_TRAVERSED ;
             /**********************/
                访问root ;
                 if ( root  == end  )
                 {
                    real_end  =  true ;
                     break ;
                 }
             /**********************/
                 if(right [root ]  == NIL)
                 {
                    state  = RIGHT_TRAVERSED ;
                 }
                 else
                 {
                    root  = right [root ] ;
                    state  = LEFT_NOT_TRAVERS ;
                 }
                 break ;

             //右子树处理完了的话,向上回溯,这是关键的地方。另外一个关键的地方是访问
             //节点之后要判断
             case RIGHT_TRAVERSED ;
                 //处理是从右子树回溯上来的情况,如果是从右子树回溯上来的,下一个将要处理的
                 //节点,即当前节点的父节点的状态是RIGHT_TRAVERSED,也就是说它的右子树已经
                 //处理过了,否则是LEFT_TRAVERSED,也就是说它的右子树还没有处理。
                 if ( right [parent [root ] ]  ! = root  )
                    state  = LEFT_TRAVERSED ;
                root  = parent [root ] ;
                 break ;
         }
     }
}
/******************* in-order end **********************************/

pre-order(前序)

/******************* pre-order start ******************************/
if (root  == NIL )
    结束 ;
//找到遍历的结束点end.
while (  true  )
{
     if ( right [root ]  ! = NIL  )
        root  = right [root ] ;
     else  if (left [root ]  ! = NIL )
        root  = left [root ] ;
     else
         break ;
}
state  = LEFT_NOT_TRAVERS ;
real_end  =  false ;
while (  !real_end )
{
     if (left [root ]  ! = NIL )
     {
         switch (state )
         {
             case LEFT_NOT_TRAVERS :
                 /****************/
                访问root ;
                 if ( root  = end  )
                 {
                    real_end  =  true ;
                     break ;
                 }
                 /****************/
                root  = left [root ] ;
                state  = LEFT_NOT_TRAVERS ;
                 break ;

             case LEFT_TRAVERSED :
                 if  (right [root ]  == NIL )
                 {
                    state  = RIGHT_TRAVERSED ;
                 }
                 else
                 {
                    root  = right [root ] ;
                    state  = LEFT_NOT_TRAVERS ;
                 }
                 break ;

             case RIGHT_TRAVERSED :
                 if ( right [parent [root ] ]  ! = root  )
                    state  = LEFT_TRAVERSED ;
                root  = parent [root ] ;
                 break ;
         }
     }
     else
     {
         switch (state )
         {
             case LEFT_NOT_TRAVERS ;
                 /****************/
                访问root ;
                 if ( root  == end  )
                 {
                    real_end  =  true ;
                     break ;
                 }
                 /****************/
                state  = LEFT_TRAVERSED ;
                 break ;

             case LEFT_TRAVERSED ;
                 if(right [root ]  == NIL)
                 {
                    state  = RIGHT_TRAVERSED ;
                 }
                 else
                 {
                    root  = right [root ] ;
                    state  = LEFT_NOT_TRAVERS ;
                 }
                 break ;

             case RIGHT_TRAVERSED ;
                 if ( right [parent [root ] ]  == root  )
                    state  = LEFT_TRAVERSED ;
                root  = parent [root ] ;
                 break ;
         }
     }
}
/******************* pre-order end ********************************/

post-order(后序)

/******************* post-order start ******************************/
if (root  == NIL )
    结束 ;
//找到遍历的结束点end.
end  = root ;
// 记录初始状态
state  = LEFT_NOT_TRAVERS ;
real_end  =  false ;
while (  !real_end  )
{
     if (left [root ]  ! = NIL )
     {
         switch (state )
         {
             case LEFT_NOT_TRAVERS :
                root  = left [root ] ;
                state  = LEFT_NOT_TRAVERS ;
                 break ;

             case LEFT_TRAVERSED :
                 if  (right [root ]  == NIL )
                 {
                    state  = RIGHT_TRAVERSED ;
                 }
                 else
                 {
                    root  = right [root ] ;
                    state  = LEFT_NOT_TRAVERS ;
                 }
                 break ;

             case RIGHT_TRAVERSED :
                 /****************/
                访问root ;
                 if ( root  = end  )
                 {
                    real_end  =  true ;
                     break ;
                 }
                 /****************/
                 if ( right [parent [root ] ]  ! = root  )
                    state  = LEFT_TRAVERSED ;
                root  = parent [root ] ;
                 break ;
         }
     }
     else
     {
         switch (state )
         {
             case LEFT_NOT_TRAVERS ;
                state  = LEFT_TRAVERSED ;
                 break ;

             case LEFT_TRAVERSED ;
                 if(right [root ]  == NIL)
                 {
                    state  = RIGHT_TRAVERSED ;
                 }
                 else
                 {
                    root  = right [root ] ;
                    state  = LEFT_NOT_TRAVERS ;
                 }
                 break ;

             case RIGHT_TRAVERSED ;
                 /****************/
                访问root ;
                 if ( root  == end  )
                 {
                    real_end  =  true ;
                     break ;
                 }
                 /****************/
                 if ( right [parent [root ] ]  ! = root  )
                    state  = LEFT_TRAVERSED ;
                root  = parent [root ] ;
                 break ;
         }
     }
}
/******************* post-order end ********************************/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值