1. 程式人生 > >(二叉樹)(棧應用)二叉樹的中序遍歷

(二叉樹)(棧應用)二叉樹的中序遍歷

題目描述

題目就不用多說了,即是對二叉樹進行左-根-右的中序遍歷。

題目分析

不管是對二叉樹進行中序遍歷,還是前序或者後序遍歷,最簡單的方法也是最容易想的方法就是遞迴,遞迴程式碼如下:

vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        run_LVR(root,result);
        return result;
        
    }
    void run_LVR(TreeNode* V,vector<int> & recorder){
        if(!V) return;
        run_LVR(V->left,recorder);
        recorder.push_back(V->val);
        run_LVR(V->right,recorder);
    }

遞迴演算法是比較簡單的,不過如果遞迴的深度太深,會造成堆疊溢位,因此可以考慮使用顯式棧,雖然遞迴呼叫也是使用的棧,但是系統呼叫棧較小,容易造成堆疊溢位,使用顯式棧可以很好的模擬系統呼叫棧但是空間更大。那麼該如何實現呢?
使用顯式棧進行二叉樹遍歷是很常見的DFS用例,按照DFS的一般做法即是先將根結點放入棧中,然後不斷訪問棧頂結點,先將棧頂結點儲存後彈出,然後將儲存後的棧頂結點進行左-棧頂結點-右遍歷,然後放入棧中,需要注意的是,由於棧先進後出的特點,這裡放置結點時應當從右結點開始放入棧中。由於是遍歷,因此每個結點都會經歷壓入和彈出的過程,而對於每個被彈出過的“棧頂結點”來說,都總共會入棧兩次,第一次是作為父母結點的子結點入棧,第二次是作為中序遍歷時入棧,為了儲存最終的遍歷結果,那麼就應當在第二次遍歷到結點時將結點值儲存到最終的遍歷結果中,如果結點已經是根結點了,那麼直接儲存即可。程式如下:

vector<int> inorderTraversal(TreeNode* root) {
        if(!root)return {};
        vector<int>res;
        stack<TreeNode*>Nodes;
        unordered_set<TreeNode*>m;
        
        if(root->right)Nodes.push(root->right);
        Nodes.push(root);
        m.insert(root);
        if(root->left)Nodes.push(root->left);
        
        while(!Nodes.empty())
        {
            TreeNode* temp=Nodes.top();
            Nodes.pop(); 
            if((!temp->left&&!temp->right)||m.find(temp)!=m.end())res.push_back(temp->val);
            else if(m.find(temp)==m.end())
            {
                if(temp->right)Nodes.push(temp->right);
                Nodes.push(temp);
                if(temp->left)Nodes.push(temp->left);              
                m.insert(temp);
            }
        }
        return res;
    }

前序遍歷與後續遍歷與中序遍歷相比只需交換結點入棧順序即可,在此不作贅述。