二叉树的前序、中序、后序遍历非递归

二叉树的前序递归、中序递归、后序递归不说了,是人都会写。

前序非递归:

前序是中-》左-》右,那么对于当前节点cur来说,我们要先把cur的值放入结果数组。再深入其左子树。左子树遍历完后,再深入其右子树。

那么显然再我们深入其左子树前,需要保存当前节点cur,因为之后还要遍历cur的右子树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        stack<TreeNode*> sta;
        vector<int> res;
        auto cur=root;
        while(cur or not sta.empty()){
            if(cur==nullptr){
                cur=sta.top()->right;
                sta.pop();
            }
            else{
                res.emplace_back(cur->val);
                sta.push(cur);
                cur=cur->left;
            }
        }
        return res;
    }
};

中序非递归:

和前序都差不多的,只不过顺序改为:左-》中-》右。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> sta;
        vector<int> res;
        auto cur=root;
        while(cur or not sta.empty()){
            if(cur==nullptr){
                res.emplace_back(sta.top()->val);
                cur=sta.top()->right;
                sta.pop();
            }
            else{
                sta.push(cur);
                cur=cur->left;
            }
        }
        return res;
    }
};

后序非递归:

这个有点难度,因为什么呢,后序顺序是:左-》右-》中。所以对于一个节点cur,我们先遍历其左子树,那首先要把cur入栈,对吧?然后我们还要遍历cur的右子树。最后再遍历cur。

问题就是遍历完左子树后,我们会回去找cur(为了找cur的右子树)。

遍历完右子树后,也会回去找cur(为了遍历cur本身,因为左-》右-》中嘛)。

那如何区别这两种情况呢?

可以使用一个bool变量用来指示我们是否遍历完当前节点的子树:

struct point{
        TreeNode* node;
        bool FinishSubtree;
        point(TreeNode* x){
            node=x;
            FinishSubtree=false;//该值为false,说明还没有遍历完左右子树。为true则表示遍历完了左右子树
        }
        point():node(nullptr),FinishSubtree(false){}
    };

如上面注释所说,对于一个节点cur,我们先入栈cur。然后遍历其左子树,此时cur对应的标记应该是false,因为还没有遍历右子树。

等我们遍历完cur的左子树后,回来找cur的右子树时,我们把cur的标记置为true,表明这个cur节点的子树已经被遍历完了(虽然此时右子树还没遍历,但我们接下来第一步会先遍历其右子树,再回来找cur,这个时候cur的左右子树确实已经被遍历完了)。这样我们遍历好cur的右子树后,回来再输出cur的val。这样正好满足左-》右-》中的顺序。最终我们终于可以pop掉cur了,因为cur及其左右子树都遍历完毕了。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    struct point{
        TreeNode* node;
        bool FinishSubtree;
        point(TreeNode* x){
            node=x;
            FinishSubtree=false;//该值为false,说明还没有遍历完左右子树。为true则表示遍历完了左右子树
        }
        point():node(nullptr),FinishSubtree(false){}
    };
    vector<int> postorderTraversal(TreeNode* root) {
        stack<point> sta;
        vector<int> res;
        TreeNode* cur=root;
        point p;
        while(cur or not sta.empty()){
            if(cur==nullptr){
                p=sta.top();
                if(p.FinishSubtree==false){//左子树完成
                    sta.top().FinishSubtree=true;
                    //更新标记为true,这样等右子树遍历完后,堆顶的左右子树就都遍历完了,堆顶可以直接pop
                    cur=p.node->right;
                }
                else{
                    res.emplace_back(sta.top().node->val);
                    sta.pop();
                }
            }
            else{
                sta.push(point(cur));
                cur=cur->left;
            }
        }
        return res;
    }
};

 

posted @ 2020-03-18 15:52  NeoZy  阅读(268)  评论(0)    收藏  举报