二叉树的遍历(非递归)

三种遍历:

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

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

    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/ 

posted @ 2020-03-26 15:45  Rogn  阅读(84)  评论(0编辑  收藏