树的前中后序遍历-非递归的迭代写法

文章详细介绍了如何使用栈来实现二叉树的前序、中序和后序遍历,以避免递归导致的栈溢出问题。在前序遍历中,先访问节点,然后遍历左子树;在中序遍历中,子树遍历完成后访问节点;后序遍历则需要额外的prev指针来判断节点的右子树是否已访问。
摘要由CSDN通过智能技术生成

就是要我们非递归其实就是模仿递归的写法,类如递归一样遍历一棵树,但是却不是递归的写法,

防止栈溢出。

二叉树的前序遍历

先看递归代码:

void _preorderTraversal(TreeNode* root,vector<int>&v)
{
    if (root == NULL)
	{
		return;
	}
	v.push_back(root->val);
	preorderTraversal(root->_left);
	preorderTraversal(root->_right);
}


vector<int> preorderTraversal(TreeNode* root)
{
    vector<int> v;
     _preorderTraversal(root,v);
    return v;
}

        递归遍历访问到nullptr时,可以返回上一层结点,再去访问右子树。这里我们是在上一级栈帧中保存了直系父节点才做到,当该父节点结束以后代表他的左右结点都访问完毕,然后再返回他的上一层结点(B的左右结点访问完毕,返回到A,再去访问C)为什么能再次返回呢?因为每一层栈帧保存了一个父节点。我们的非递归就是要做到这样的情况。类似栈帧的完成方法实现,这就要使用到我们的栈了。

我们规定了遍历顺序都是先遍历左子树再遍历右子树,所以我们的前序遍历就要先访问左子树

 每到一个非空树时就要将根结点保存在栈中.然后继续访问左子树cur=cur->left

当访问到左树为空时就将栈顶元素拿出来并且删除栈顶元素,将拿出的二叉树根指针的右子树赋值给遍历指针

 cur遇nullptr时继续取栈顶元素并删除栈顶,右树继续赋值给cur

然后压入元素E,cur=cur->left

cur==nullptr结束循环,取栈顶元素,将元素的右树赋值给cur,并pop栈。  

cur==nullptr结束循环,取栈顶元素,将元素的右树赋值给cur,并pop栈。  

 最后访问结束后cur==nullptr,stack也是空栈。

 

访问结束,退出循环。

查看代码:

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode*cur=root;
        //只有栈空并且cur==nullptr才会退出循环。
        while(cur ||!st.empty())
        {
            将节点访问,并且移动到左子树
            while(cur)
            {
                //入vector就是对结点访问。
                v.push_back(cur->val);
                st.push(cur);
                cur=cur->left;
            }
            cur=st.top()->right;
            st.pop();
        }
        return v;
    }
};

中序遍历

中序遍历的迭代写法类似于前序迭代代码。改变访问位置即可,前序遍历都是来到一个结点先访问在去左子树,而中序就是子树访问完毕后再去访问根结点。在栈top时访问该元素即可。

看中序代码:

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
    stack<TreeNode*> st;
        vector<int> v;
        TreeNode*cur=root;
        while(cur ||!st.empty())
        {
            while(cur)
            {
                //结点压栈,但是不访问。
                st.push(cur);
                cur=cur->left;
            }
            
            TreeNode* top=st.top();
            //取出栈顶元素后访问就是中序访问
            v.push_back(top->val);
            //访问后将top的右子树赋值给cur
            cur=top->right;
            st.pop();
        }
        return v;
    }
};

后序遍历(重点)

画图+代码理解。

    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode*cur=root;
        TreeNode*prev=nullptr;
        while(cur ||!st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            }
         //......

前面代码和中序遍历一样,但是我们加了一个prev指针,用来保存返回前的结点

当我们访问到cur==nullptr是取栈顶元素进行操作。

auto top=st.top();
if(top->right==nullptr||top->right==prev)
{
    v.push_back(top->val);
    prev=top;
    st.pop();
}
else
{
    cur=top->right;
}

 top->right==nullptr:当我们的结点的左边访问完毕后查看右边是否为空如果为空,就表示对结点数据访问。

top->right==prev:prev保存取出上一层取出栈顶的元素,我们查看他是否为这次栈顶结点的右结点,如果等于就意味着该节点的右子树访问完毕。

有点抽象吧?画个图,我也活动以下脑子。

 

 

 

 

 此刻!!大循环判断不成立退出循环

结束循环返回数据。树以后序遍历结束!!!

完整代码:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode*cur=root;
        TreeNode*prev=nullptr;
        while(cur ||!st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            }
            auto top=st.top();
            if(top->right==nullptr||top->right==prev)
            {
                v.push_back(top->val);
                prev=top;
                st.pop();
            }
            else
            {
                cur=top->right;
            }
        }
        return v;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云的小站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值