二叉树前中后序遍历_(非递归)

Posted LHlucky_2

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树前中后序遍历_(非递归)相关的知识,希望对你有一定的参考价值。

1. 前序遍历

  • Leetcode例题链接:link
    在这里插入图片描述
    前序遍历:(根左右)

  • 8->5->2->6->10->9

用栈的非递归做法如下图所示:
在这里插入图片描述
过程概述:

  1. 先将树从根节点开始往左遍历,将遍历的结点入栈,且遍历的时候将结点里面的值入到数组中(保证根先被存储)。
  2. 当走到最左边以后,开始访问栈顶元素。 并将栈顶元素删除(已经被存储过)。
  3. 然后让cur = top -> right,让栈顶元素的右树结点作为cur,则访问方式和刚才root结点的过程一二是一样的,(将右数作为一个新的树,在执行一二操作,子问题操作方法一样处理方式)。

代码实现:

/**
 * 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<int> preorderTraversal(TreeNode* root) {
        vector<int> vv;
        stack<TreeNode*> st;
        TreeNode *cur = root;
        while(cur || !st.empty())
        {
            while(cur)
            {
                st.push(cur);
                vv.push_back(cur->val);//先从前往左走,相当于先保留了根节点并且遍历了左节点 根左右。
                cur = cur -> left;
            }

            TreeNode *top = st.top();//取栈顶元素,也就是树的最左结点。
            st.pop();

            cur = top -> right;//取最左结点的右结点。子问题一样的处理办法。
        }
        return vv;
    }
};

代码二:(不做详解,可画图自行参悟,本人推荐上面方法)

 *     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<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> ret;
        if(root == nullptr)
        {
            return ret;
        }
        st.push(root);
        while(!st.empty())
        {
            TreeNode *Node = st.top();
            st.pop();
            ret.push_back(Node->val);
            if(Node->right)
            st.push(Node->right);
            if(Node->left)
            st.push(Node->left);
        }

        return ret;
    }
};

2. 中序遍历

  • Leetcode例题链接:link
    在这里插入图片描述
    中遍历:(左根右)

  • 2->5->6->8->9->10

用栈的非递归做法如下图所示:
在这里插入图片描述

过程概述:

  1. 先将树从根节点开始往左遍历,将遍历的结点入栈,但遍历的时候将结点里面的值不入到数组中(和前序有差别的地方)。
  2. 当走到最左边以后,开始访问栈顶元素。并将栈顶元素的值入到数组中, 并将栈顶元素删除(保证左先被存储,且已经被存储过删除掉)。
  3. 然后让cur = top -> right,让栈顶元素的右树结点作为cur,则访问方式和刚才root结点的过程一二是一样的,(将右数作为一个新的树,在执行一二操作,子问题操作方法一样处理方式)。

代码实现:

/**
 * 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<int> inorderTraversal(TreeNode* root) {
        vector<int> vv;
        stack<TreeNode*> st;
        TreeNode *cur = root;
        while(cur || !st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur=cur->left;
            }
            //当把所有的左节点入栈以后,取栈顶元素就是最左结点,这个时候再把值入到子数组中。
            TreeNode *top = st.top();
            st.pop();
            vv.push_back(top->val);

            cur = top -> right;//左边处理结束以后再去处理右边子问题解决方法一样。
        }
        return vv;
    }
};

代码二:(不做详解,可画图自行参悟,本人推荐上面方法)

/**
 * 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<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode*> st;
        TreeNode* cur = root;

        while(cur != nullptr || !st.empty())
        {
            if(cur != nullptr)
            {
                st.push(cur);
                cur = cur->left;//左
            }
            else
            {
                cur = st.top();
                st.pop();

                ret.push_back(cur->val);//中
                cur = cur->right;//右
            }
        }
        return ret;
    }
};

3. 后序遍历

  • Leetcode例题链接:link
    在这里插入图片描述
    后序遍历:(左右根)
  • 2->6->5->9->10->8

用栈的非递归做法如下图所示:
在这里插入图片描述

过程概述:

  1. 先将树从根节点开始往左遍历,将遍历的结点入栈,遍历的时候将结点里面的值不入到数组中。
  2. 当走到最左边以后,开始访问栈顶元素,当栈顶元素top -> light == nullptr时 将栈顶元素的值入到数组中,并将top结点删除。(先入左结点的值)
  3. 则下一个栈顶元素时父结点,判断父结点有没有右树,如果有右数,则将这个结点的值不入数组,先访问右数结点,并将访问的结点由prev保存。当top->light==prev时则说明父节点是第二次访问且右数已经访问完毕。(保证左右根)
  4. 以上两个条件都不满足让cur = top -> right,让栈顶元素的右树结点作为cur,则访问方式和刚才root结点的过程一二是一样的,(将右数作为一个新的树,在执行一二操作,子问题操作方法一样处理方式)。

代码实现:

/**
 * 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<int> postorderTraversal(TreeNode* root) {
        vector<int> vv;
        stack<TreeNode*> st;
        TreeNode *prev = nullptr;//记录之前访问的结点为记录夫结点是第几次访问做准备
        TreeNode*cur = root;

        while(cur || !st.empty())
        {
            while(cur)//先入左节点
            {
                st.push(cur);
                cur = cur -> left;
            }

            TreeNode *top = st.top();
            if( top->right == nullptr ||  top -> right == prev)//数组入数据的条件
            {
                vv.push_back(top -> val);
                st.pop();

                prev = top;//记录访问结点,为了判断top -> right == prev做准备。
                cur = nullptr;
            }
            else
            {
                cur = top -> right;
            }
        }
        return vv;
    }
};

代码二:(不做详解,可画图自行参悟,本人推荐上面方法)

/**
 1. Definition for a binary tree node.
 2. struct TreeNode {
 3.     int val;
 4.     TreeNode *left;
 5.     TreeNode *right;
 6.     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 7.     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 8.     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 9. };
 */

 //递归法,利用前序遍历,中左右,改变为中右左,在一反转。左右中即可。
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ret;
        stack<TreeNode*> st;

        if(root)
        {
            st.push(root);
        }

        while(!st.empty())
        {
            TreeNode* Node = st.top();
            st.pop();
            ret.push_back(Node->val);//处理中值。

            if(Node->left)//后处理左,则先入左。
            {
                st.push(Node->left);
            }
            if(Node->right)//先处理右,则后入右。
            {
                st.push(Node->right);
            }
        }
        reverse(ret.begin(),ret.end());
        return ret;
    }
};

总结

  1. 以上代码的总体框架基本一样,只是在往数组中入结点值的时机和条件有所差异。
  2. 本人推荐每种遍历的代码一,代码风格相似,掌握一种,别的都可以掌握。
  3. 每种遍历的代码二也是非递归遍历,也很简单,不做详解,可画图模拟。

以上是关于二叉树前中后序遍历_(非递归)的主要内容,如果未能解决你的问题,请参考以下文章

二叉树前中后序遍历的实现(递归和非递归版)

二叉树前中后序遍历非递归实现

二叉树前中序非递归遍历

二叉树前中后序遍历递归转循环

leetcode算法总结 —— 二叉树前中后序遍历(迭代和递归两种解法)

二叉树前中后序遍历递归法&迭代法