二叉树的遍历——递归和迭代

许久没有用到二叉树,也是有些生疏了,虽然写递归没问题,但迭代还是有点难度。

统一节点定义:

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) {}
};
normal定义

分递归和迭代排版吧。

【递归】

前序遍历:根左右

class Solution
{
public:
    vector<int> ans;
    vector<int> preorderTraversal(TreeNode *root)
    {
        if (!root)
            return ans;
        ans.emplace_back(root->val);
        if (root->left)
            preorderTraversal(root->left);
        if (root->right)
            preorderTraversal(root->right);
        return ans;
    }
};
前序递归

中序遍历:左根右

class Solution
{
public:
    vector<int> ans;
    vector<int> inorderTraversal(TreeNode *root)
    {
        
        if (!root)
            return ans;
        if (root->left)
            inorderTraversal(root->left);
        ans.emplace_back(root->val);
        if (root->right)
            inorderTraversal(root->right);
        return ans;
    }
};
中序递归

后序遍历:左右根

class Solution
{
public:
    vector<int> ans;
    vector<int> postorderTraversal(TreeNode *root)
    {
        if (!root)
            return ans;
        if (root->left)
            postorderTraversal(root->left);
        if (root->right)
            postorderTraversal(root->right);
        ans.emplace_back(root->val);
        return ans;
    }
};
后序遍历

----------------------------------------------分割线------------------------------------------

【迭代】

前序:写了两个版本,一个是自己直接写出来的(更好理解),一个是基于二叉树迭代模板

class Solution
{
public:
    vector<int> preorderTraversal(TreeNode *root)
    {
        stack<TreeNode *> st;
        vector<int> ans;
        st.push(root);
        //刚开始用的是vector想用下标,但写着变成了层序遍历
        //前序遍历还是得用栈来模拟
        while (st.size() && st.top())
        {
            TreeNode *n = st.top();
            st.pop();
            ans.emplace_back(n->val);
            //后进先出,所以得是右左
            if (n->right)
                st.push(n->right);
            if (n->left)
                st.push(n->left);
        }
        return ans;
    }
};
mine
class Solution
{
public:
    vector<int> preorderTraversal(TreeNode *root)
    {
        vector<int> ans;
        stack<TreeNode *> st;
        TreeNode *n = root;
        while (!st.empty() || n != nullptr)
        {
            while (n != nullptr)
            {
                ans.emplace_back(n->val);
                st.emplace(n);
                n = n->left;
            }
            n = st.top()->right;
            st.pop();
        }
        return ans;
    }
};
standard

中序:

tips:前序是在   循环左子节点   时候就直接放入,中序是   循环左子节点   后   的每一次找右子节点   时候放入。

class Solution
{
public:
    vector<int> inorderTraversal(TreeNode *root)
    {
        stack<TreeNode *> st;
        vector<int> ans;
        TreeNode *n = root;
        while (!st.empty() || n != nullptr)
        {
            while (n != nullptr)
            {
                st.emplace(n);
                n = n->left;
            }
            ans.emplace_back(st.top()->val);
            n = st.top()->right;
            st.pop();
        }
        return ans;
    }
};
standard

后序:

也是最难的,我不熟练的情况下空想做了一个小时,最好还是打个草稿画一画二叉树,更方便构思逻辑

重点理解顺序是“左右根”,

在循环左子节点入栈后,在对当前(根)节点是否出栈,需要考虑右子节点的情况

1.没有右子节点,那么直接出栈

2.有右子节点,分是否已经遍历过右子节点:

  (先说逻辑)

  a.如果已经遍历,那么也是直接出栈

  b.如果还未遍历,那么将  当前节点  转移到  右子节点  即可,不用入栈一次的原因是,在转移到  该节点  的  右子节点  以后,所执行的操作是  先  循环左子节点  入栈,是会将  当前节点(也就是右子节点)  一并入栈的。

  那么问题变成了,如何考虑是否已经遍历的问题,answer——添加一个pre标记变量:在每一次出栈的时候,用pre存一下当前的出栈元素即可。

class Solution
{
public:
    vector<int> postorderTraversal(TreeNode *root)
    {
        vector<int> ans;
        stack<TreeNode *> st;
        TreeNode *n = root, *pre = nullptr;
        while (!st.empty() || n != nullptr)
        {
            while (n != nullptr)
            {
                st.emplace(n);
                n = n->left;
            }
            n = st.top()->right;
            if (n == nullptr || pre == n)
            {
                n = nullptr;
                pre = st.top();
                ans.emplace_back(st.top()->val);
                st.pop();
            }
        }
        return ans;
    }
};
standard

over,虽然是很基础且很早就学过的数据结构,但是还是生疏了,记录一下。

另外补充一个层序遍历:(这种处理在图论里也有用到)

 

class Solution
{
public:
    vector<vector<int>> levelOrder(TreeNode *root)
    {
        vector<vector<int>> ans(0);
        queue<TreeNode *> q;
        if (root == nullptr)
            return ans;
        q.push(root);
        int n, id = -1;
        while (q.size())
        {
            n = q.size();
            id++;
            ans.emplace_back(vector<int>(0));
            for (int i = 0; i < n; ++i)
            {
                TreeNode *n = q.front();
                q.pop();
                ans[id].emplace_back(n->val);
                if (n->left)
                    q.push(n->left);
                if (n->right)
                    q.push(n->right);
            }
        }
        return ans;
    }
};
层序遍历

 

 

 

posted @ 2022-02-22 17:51  Renhr  阅读(43)  评论(0)    收藏  举报