树的先序、中序、后序遍历非递归实现

1. 树的后序遍历

对照《将递归函数转换为非递归形式》的“5. 去掉goto后优化的非递归实现步骤”,可以实现树的后序遍历非递归函数:

enum Tags{ROOT,LEFT,RIGHT};                         //Tags对应《将递归函数转换为非递归形式》提到的rd
template<typename Comparable>
class ELEM
{
public:
    typename BinarySearchTree<Comparable>::_BinaryNode* point;
    Tags tag;
};

template<typename Comparable>
void BinarySearchTree<Comparable>::postOrderTraverStack(BinaryNode* t)const
{

    std::stack<ELEM<Comparable> > s;
    ELEM<Comparable> element,tmp;
    tmp.point = t;
    tmp.tag = ROOT;
    s.push(tmp);                                    // 步骤(1):对根节点压栈
    do
    {
        while( (element = s.top()).point != NULL)   //步骤(2):对根节点不断向下搜索,直到满足递归出口条件。这里的出口条件为:element.pointer = NULL
        {
            tmp.point = element.point->left;
            tmp.tag = LEFT;
            s.push(tmp);
        }
                                                   //因为对于出口条件element.point == NULL,不需要做任何操作,所以步骤(3)省略
        while( (element = s.top()).tag == RIGHT)   //步骤(4):如果当前节点是父节点最后一个节点,则不断上溯,直到找到不是父节点最后一个节点的祖先节点
        {
            s.pop();
            element = s.top();
            (element.point)->visit();
        }

        if( (element = s.top()).tag == LEFT)       //步骤(5):如果当前节点不是父节点最后一个节点,把兄弟节点压栈
        {
            s.pop();
            element = s.top();
            tmp.point = element.point->right;
            tmp.tag = RIGHT;
            s.push(tmp);
        }
    }while( (element = s.top()).tag != ROOT); //步骤(4)上溯的过程可能到达根节点。
    s.pop();
}
2. 树的先序遍历、中序遍历简化处理

我们同样也可以严格按照上面的步骤写出先序遍历和中序遍历的非递归函数。不过由于先序遍历和中序遍历递归函数调用了最后一个递归子函数(右节点)后不需要再对当前函数进行相关处理,也就是说左节点处理完后,可以将左节点和父节点先从堆栈中删除,然后再对右节点入栈,这样右节点就占据了父节点的位置。具体见下面两幅图,图2将图1的C1、 D1删除只剩下D2,这时相当于D2占据了父节点C1的位置,由于C1是B1的左节点,所以将C1、 D1删除后新压入栈的D2一定是它的新回溯节点B1的左节点。所以就不用再考虑步骤(4)了。从而简化了递归到非递归的转换过程。
图1
这里写图片描述

3. 先序遍历非递归代码:
template<typename Comparable>
void BinarySearchTree<Comparable>::preOrderTraverStack(BinaryNode* t)const
{
    std::stack<BinaryNode*> s;           
    s.push(t);
    BinaryNode* p = NULL;                //步骤(1):对根节点压栈
    while(!s.empty())             
    {
        while( (p = s.top()) != NULL)   //步骤(2):不断遍历左节点,直到空(空为递归出口)           
        {
            p->visit();                 //访问当前节点
            s.push(p->left);    
        }
                                       //后面分两种情况:栈顶节点或为左节点或为根节点。
        s.pop();                       //空节点不需要做任何事情仅pop掉即可 
        if(!s.empty())                 //若之前的栈顶节点是根节点这里栈空,函数结束;若为左节点,后面的语句进行步骤(5)处理
        {                              //步骤(5):处理当前节点不是父节点最后一个节点即为左节点的情况
            p = s.top();             
            s.pop();                  //**右节点入栈前先删除父节点**
            s.push(p->right);   
        }
    }                              
}
4. 中序遍历非递归代码:
template<typename Comparable>
void BinarySearchTree<Comparable>::inOrderTraverStack(BinaryNode* t)const
{
    std::stack<BinaryNode*> s;
    s.push(t);
    BinaryNode* p = NULL;
    while(!s.empty())
    {
        while( (p = s.top()) != NULL)
        {
            s.push(p->left);
        }
        s.pop();
        if(!s.empty())
        {
            p = s.top();
            p->visit();
            s.pop();
            s.push(p->right);
        }
    }
}
5. 参考

《 将递归函数转换为非递归形式》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值