二叉树的非递归遍历(前序,中序,后序)

之前我们通过递归的方式来实现二叉树的:http://blog.csdn.net/zjx624bjh/article/details/78905493

采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁,但如果我们的二叉树只有左子树,而且树的高度还很深的时候,这个时候递归调用遍历的时候,栈帧空间开辟的较大,很可能造成栈溢出。但是我们一个程序中,为堆分配的空间要比栈大的多,所以对于树的遍历可采用非递归的方法,模拟栈帧调用的过程,采用栈去实现,用子问题方法来解决。
同样以这棵树为例:
这里写图片描述
(1)前序遍历
前序遍历的顺序是根节点->左子树->右子树。以下面的树为例,从根节点1一直访问到最左节点3,直到节点3的左子树为空,我们需要返回到节点2,在访问它的右子树,所以这里我们要用到栈,利用栈的后进先出规律,可以取到节点2。接下来无论树有多大,整棵树便可以用这样的子问题来解决。
具体步骤:(1)将从根节点开始最左边这条路径上的节点依次压入栈。
(2)由于3的左子树为空,所以pop3,接下来取栈顶元素2并访问其右孩子4,pop2.
(3)将4压入栈,由于4的左子树为空,pop4.
(4)取栈顶元素1,并访问其右孩子节点5,pop1.
(5)将5压入栈,访问节点5的左子树节点6,并将6压入栈.
(6)取栈顶元素6,由于节点6的右子树为空,所以pop6,同理pop5.
这里写图片描述
代码实现

//前序遍历
void _PrevOrder()
{
    Node* cur = _root;
    stack<Node*> s;
    while(cur || !s.empty())
    {
        while(cur)
        {
            cout<<cur->_data<<" ";
            s.push(cur);
            cur = cur->_left;
        }
        Node* top = s.top();
        cur = top->_right;
        s.pop();
    }
}

(1)中序遍历
对于中序遍历,将上述前序遍历稍加修改即可。
中序遍历的顺序是左子树->根节点->右子树。
具体步骤:(1)将从根节点开始最左边这条路径上的节点依次压入栈。
(2)由于3的左子树为空,访问栈顶元素3,3的右子树为空,pop3.
(3)访问栈顶元素2,取2的右孩子节点4,pop2并将4压入栈中,由于4的左子树为空,访问栈顶元素4接着pop4。
(4)访问栈顶与元素1,取1的右孩子节点5,并pop1.
(5)将5压入栈后并将5的左孩子节点6压入栈,依次访问6,5并将其pop。

这里写图片描述
代码实现:

//中序遍历
void _InOrder()
{
    Node* cur = _root;
    stack<Node*> s;
    while(cur || !s.empty())
    {
        while(cur)
        {
            s.push(cur);
            cur = cur->_left;
        }
        Node* top = s.top();
        cout<<top->_data<<" ";
        s.pop();
        cur = top->_right;
    }
}

(1)后序遍历
中序遍历的顺序是左子树->右子树->根节点。
后序遍历的难点在于:需要判断上次访问的节点是位于左子树,还是右子树。若是位于左子树,则需跳过根节点,先进入右子树,再回头访问根节点;若是位于右子树,则直接访问根节点。

这里写图片描述
代码实现:

//后序遍历
void _PosOrder()
{
    Node* cur = _root;
    Node* prev = NULL;
    stack<Node*> s;
    while(cur||!s.empty())
    {
        while(cur)
        {
            s.push(cur);//从根节点一直沿左子树方向压栈,直到最左节点的左孩子为空
            cur = cur->_left;
        }
        Node* top = s.top();
        if(top->_right == NULL || top->_right == prev)//当节点的右孩子为空或者已经访问过,便将当前节点打印后pop
        {
            cout<<top->_data<<" ";
            s.pop();
            prev = top;
        }
        else
        {
            cur = top->_right;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值