1. 程式人生 > >二叉樹的非遞迴遍歷:棧---->最簡潔,最容易版.

二叉樹的非遞迴遍歷:棧---->最簡潔,最容易版.

後序遍歷(左->右->根):需要一個標記Lastvisited

只有兩種情況才能彈出棧,1.右孩子節點為空,2.右孩子節點已經訪問過(如果沒有這條,那麼會死迴圈再次push該孩子的右節點)
/**
 * 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> postorderTraversal(TreeNode* root) {
        vector<int> res;
        if(root==NULL) return res;
        stack<TreeNode*> st;
        while(root)
        {
            st.push(root);
            root=root->left;
        }

        TreeNode* LastVisted=NULL;//標記已經訪問過的,不然會再次進棧。

        while(!st.empty())
        {
            TreeNode* top=st.top();
            if(top->right==NULL||top->right==LastVisted)//右孩子節點為空,或者右孩子節點已經訪問過。
            {
                st.pop();
                LastVisted=top;
                res.push_back(top->val);
            }else
            {
                TreeNode *p=top->right;
                while(p)
                {
                    st.push(p);
                    p=p->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) {
        vector<int> res;
        if(root==NULL) return res;
        stack<TreeNode*> st;
        while(root)
        {
            st.push(root);
            root=root->left;
        }
        while(!st.empty())
        {
            TreeNode*top=st.top();
            st.pop();
            res.push_back(top->val);

            TreeNode*p=top->right;
            while(p)
            {
                st.push(p);
                p=p->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> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if(root==NULL) return res;

        stack<TreeNode*> st;
        st.push(root);

        while(!st.empty())
        {
            TreeNode*top=st.top();
            st.pop();
            res.push_back(top->val);
            if(top->right) st.push(top->right);
            if(top->left) st.push(top->left);
        }
        return res;

    }
};


總結: 1.中序,後序遍歷,因為都是"左"在前面,所以首先要依次進棧左孩子節點,然後彈出棧開始下一步處理。 2.這裡,後序遍歷需要一個訪問標記,只有該孩子的右孩子節點為空,或者右孩子已經訪問過,才彈出棧。 3.先序遍歷,因為最先開始遍歷根節點,所以採取的策略是一邊遍歷,一邊進棧,而不是全部把左孩子進棧。