【C++进阶】迭代实现二叉树前中后序遍历

前言

我们之前学习了二叉树的递归方法来实现二叉树的前中后序遍历,但是递归实现遍历,如果递归深度过深,就可能会导致程序崩溃,我们直到,栈空间很小,所以我们今天学习使用迭代的方式来实现:

前序遍历

题目链接:力扣前序遍历

先来回顾一下递归是怎么实现的,首先遍历二叉树的根,然后是左子树,右子树,但是左子树又被分为根,左子树,右子树,所以通过递归遍历时,先去保存结点的值,再向左子树递归,后向右子树递归。
我们通过迭代来实现二叉树的遍历,本质上还是模拟递归来实现,我们将分为以下两步:

  1. 先通过循环遍历左子树,直到为空,并且将遍历过的结点存在栈中。
  2. 从栈顶拿结点,再去访问栈顶结点的右子树。

 Definition for a binary tree node.
     struct TreeNode {
     int val;
     TreeNode *left;
     TreeNode *right;
     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
  };
 
class Solution {
public:
    vector preorderTraversal(TreeNode* root) {
        TreeNode* cur = root;
        stack st;
        vector v;
        while (cur || !st.empty())
        {
            while (cur)
            {
                st.push(cur);
                v.push_back(cur->val);
                cur = cur->left;
            }
            TreeNode* top = st.top();
            st.pop();
            cur = top->right;
        }

        return v;
    }
};

中序遍历

题目链接:力扣中序遍历

中序遍历和前序遍历很像,只是保存到数组的时机不同,让我们思考一下,在前序遍历时,当一个结点出栈时,也就说明这个结点和这个结点的左子树一定以及访问过了,并且左子树中的结点也已经保存了,由于中序遍历, 是先访问左子树,然后是根,最后是右子树,所以在结点出栈之后,再去保存到vector中,就可以了。


 Definition for a binary tree node.
     struct TreeNode {
     int val;
     TreeNode *left;
     TreeNode *right;
     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
  };
 
 class Solution {
 public:
     vector inorderTraversal(TreeNode* root) {
         stack st;
         vector v;
         TreeNode* cur = root;
         while (cur || !st.empty())
         {
             while (cur)
             {
                 st.push(cur);
                 cur = cur->left;
             }


             TreeNode* top = st.top();
             st.pop();
             v.push_back(top->val);

             cur = top->right;
         }

         return v;
     }
 };

后序遍历

题目链接:力扣后序遍历

后序遍历与中序和前序有所不同,更加不容易掌握在什么时机去将节点中的数据保存到vector中,首先我们知道,后序遍历是先访问左子树,再访问右子树,最后访问根,所以要保存根结点时,必须满足要么右子树已经保存完了,要么就是右子树为空,其他和前序中序类似,只要控制栈是否为空和cur是否为空即可。


 Definition for a binary tree node.
     struct TreeNode {
     int val;
     TreeNode *left;
     TreeNode *right;
     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
  };
 
 class Solution {
 public:
     vector postorderTraversal(TreeNode* root) {
         stack st;
         vector v;
         TreeNode* cur = root;
         TreeNode* prev = nullptr;
         while (cur || !st.empty())
         {
             while (cur)
             {
                 st.push(cur);
                 cur = cur->left;
             }
             TreeNode* top = st.top();
             //当数据出栈时,说明该数据和该数据的左子树已经访问
             //而我们现在控制,第一个遍历到该数据时不出栈,只有该数据的
             //右子树为空或者该数据的右子树就是上一个遍历的结点时
             //才会进行出栈,出栈时将结点的val push到vector当中
             if (!top->right || top->right == prev)
             {
                 v.push_back(top->val);
                 prev = top;
                 cur = nullptr;
                 st.pop();
             }
             else
             {
                 //通过该条语句让该节点的右子树去调用函数,就是
                 //一个重复调用的过程,只有当栈为空并且cur为空即
                 //全部遍历完
                 cur = top->right;
             }
         }

         return v;
     }
 };

总结

今天学习了使用非递归来实现二叉树的前中后序遍历,相比递归实现有一定难度,但是多多理解也不难。

你可能感兴趣的:(C++进阶,刷题,c++,leetcode,算法)