• 二叉树的遍历(非递归)


    三种遍历:

    • 先序:根   左  右
    • 中序:左  根  右
    • 后续:左   右  根

    先看一种我认为比较秒的方法

        vector<int> postorderTraversal(TreeNode* root) {
            if(root == NULL)  return vector<int>{};
            vector<int>res;
            stack<TreeNode*>st;
            st.push(root);
            while(!st.empty())
            {
                TreeNode* p = st.top();st.pop();
                res.push_back(p->val);
                if(p->left)  st.push(p->left);     // 先左
                if(p->right)  st.push(p->right);  // 后右,这样弹出时才能先右后左
            }
             reverse(res.begin(), res.end());
            return res;
        }

    如果是先序遍历,只需改成先右后左;

    但是这种方法不能实现中序遍历。

    另外的思路是对访问过的节点进行标记,可以只标记最后一个被pop的

    1、使用一个栈,先把二叉树的右孩子压入,再把左孩子压入。这样在输出时就满足后序要求(先左后右)。

    2、当某个节点的左孩子或者右孩子都为NULL时,可以访问。此外记录当前节点p的上一个节点last,因为当p的左右孩子都已访问过时,轮到p被访问,设置last可标志p的左右孩子是否都被访问过了。即为 if((p->right == NULL && p->left == last) || p->right == last) 

        vector<int> postorderTraversal(TreeNode* root) {
            if(root == NULL)  return vector<int>{};
            vector<int>res;
            stack<TreeNode*>st;
            st.push(root);
            TreeNode* pre;  // 记录上一个pop的节点
            while(!st.empty())
            {
                TreeNode* p = st.top();
                if((p->left == NULL && p->right == NULL) || (p->left == pre && p->right == NULL) || (p->right == pre))
                {
                    res.push_back(p->val);
                    pre = p;
                    st.pop();
                }
                else
                {
                    if(p->right)  st.push(p->right);
                    if(p->left)  st.push(p->left);
                } 
            }
            return res;
        }

    或者用unordered_map进行标记,

    一种统一的写法:

    二叉树的遍历都可以借助栈结构使用DFS算法完成

    首先是最简单的先序遍历,父>左>右。见144题 。
    每次入栈前先将父节点加入结果列表,然后左节点入栈。
    当左子树遍历完后,再遍历右子树。

    class Solution:
        def preorderTraversal(self, root: TreeNode) -> List[int]:
            res = []  #结果列表
            stack = []  #辅助栈
            cur = root  #当前节点
            while stack or cur:
                while cur:  #遍历到最后一层
                    res.append(cur.val)  
                    stack.append(cur)
                    cur = cur.left
                top = stack.pop()  #此时该节点的左子树已经全部遍历完
                cur = top.right  #对右子树遍历
            return res

    接着来看后序遍历,左>右>父。见145题 。
    能不能借助先序遍历的思路来呢,我们将上面的顺序翻转过来得到,父>右>左。
    所以现在可以按照之前的方法遍历,最后把结果翻转一下。

    class Solution:
        def postorderTraversal(self, root: TreeNode) -> List[int]:
            res = []
            stack = []
            cur = root
            while stack or cur:
                while cur:
                    res.append(cur.val)
                    stack.append(cur)
                    cur = cur.right  #先将右节点压栈
                top = stack.pop()  #此时该节点的右子树已经全部遍历完
                cur = top.left  #对左子树遍历
            return res[::-1]  #结果翻转

    最后来看下中序遍历, 左>父>右。见94题 。
    与先序遍历不同的是,出栈时才将结果写入列表。

    class Solution:
        def inorderTraversal(self, root: TreeNode) -> List[int]:
            res = []
            stack = []
            cur = root
            while stack or cur:
                while cur:
                    stack.append(cur)
                    cur = cur.left
                top = stack.pop() #此时左子树遍历完成
                res.append(top.val)  #将父节点加入列表
                cur = top.right #遍历右子树
            return res

    参考链接:

    1. https://blog.csdn.net/exceptional_derek/article/details/17551459

    2. https://www.cnblogs.com/moxiangfeng/p/10738591.html

    3. https://leetcode-cn.com/problems/binary-tree-inorder-traversal/solution/liang-ta-lai-liao-ta-dai-zhao-san-xiong-di-lai-lia/ 

  • 相关阅读:
    docker 会这些也够
    Linux 学会这些基本可以啦
    xxxxxxxxx
    Angular
    mongo
    node
    git clone 解决Permission Denied (publickey)问题
    vue项目如何刷新当前页面
    vue——动态路由以及地址传参
    vue 单页应用点击某个链接,跳转到新页面的方式
  • 原文地址:https://www.cnblogs.com/lfri/p/12574888.html
Copyright © 2020-2023  润新知