首頁 > 軟體

C++二元樹的前序中序後序非遞迴實現方法詳細講解

2023-03-09 06:05:09

二元樹的前序遍歷

前序遍歷的順序是根、左、右。任何一顆樹都可以認為分為左路節點,左路節點的右子樹。先存取左路節點,再來存取左路節點的右子樹。把存取左路節點的右子樹看成一個子問題,就可以完整遞迴存取了。

先定義棧st存放節點、v存放值,TreeNode* cur,cur初始化為root。

當cur不為空或者棧不為空的時候(一開始棧是空的,cur不為空),迴圈繼續:先把左路節點存放進棧中,同時把值存入v中,一直迴圈,直到此時的左路節點為空,存取結束。在彈出棧頂元素top,把top->right賦值給我們的cur,就可以轉化成子問題去存取左路節點的右子樹了。

  • 棧st不為空說明此時還有左路節點的右子樹還沒存取,cur不為空說明此時還有樹要去存取。當兩個同時為空時,迴圈結束,最終得到前序遍歷。
  • 一個節點出棧說明這個節點及其左子樹已經存取完了,因為我們是先把左路節點存入棧中,此時還剩右子樹沒有存取。
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode*cur = root;
        while(!st.empty()||cur)
        {
            //左路節點
            while(cur)
            {
                st.push(cur);
                v.push_back(cur->val);
                cur = cur->left;
            }
            //左路節點右子樹
            TreeNode* top = st.top();
            st.pop();
            cur = top->right;//轉化成子問題存取右子樹
        }
        return v;
    }
};

二元樹的中序遍歷

中序遍歷是左、根、右。左子樹存取完之後才能去存取根。左路節點一直走直到左子樹存取完,入棧的過程中不去進行存取(存放數值到v中),當左路節點出棧之後,也就是從棧中彈出進行存取。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode*cur = root;
        while(cur||!st.empty())
        {
            while(cur)
            {
                //不存取
                st.push(cur);
                cur = cur->left;
            }
            TreeNode*top = st.top();
            //進行存取
            v.push_back(top->val);
            st.pop();
            cur = top->right;
        }
        return v;
    }
};

二元樹的後序遍歷

後序的遍歷順序是左、右、根。與前面的相比,比較麻煩,我們需要把左子樹和右子樹存取完再去存取根。我們定義一個棧,在棧裡面取到一個節點時:右子樹是否存取過,如果沒有存取,迭代子問題存取,如果存取過了,則存取這個根節點,pop出棧

如果top的右子樹為空或者右子樹已經存取過了(上一個存取節點是右子樹的根),那麼說明右子樹不用存取或者存取過了,可以存取根top;當右子樹不為空,且沒有存取過,則迭代子問題存取。

通過prev來判斷上一次存取的節點:如果prev等於top->right時,表示棧頂節點的右子樹已經存取過了,可以彈出棧頂節點並存取它。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> v;
        stack<TreeNode*> st;
        TreeNode*cur = root;
        TreeNode*prev = nullptr;
        while(cur||!st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur = cur->left;
            }
            TreeNode*top = st.top();
            //top的右子樹為空,或者右子樹已經存取過了(上一個存取節點時右子樹的根)那麼說明右子樹不用存取或者存取過了,可以存取根top
            //右子樹不為空,且沒有存取, 則迭代子問題存取
            if(top->right==nullptr||top->right==prev)
            {
                st.pop();
                v.push_back(top->val);
                prev = top;
            }
            else
            {
                cur = top->right;
            }
        }
        return v;
    }
};

總結

二元樹的前序遍歷、中序遍歷、後序遍歷的非遞迴遍歷三種方法都是類似的,差別在於存取棧頂的元素的時機不同,存取控制不同。其中前序和中序大致相同,而後序需要去進行判斷棧頂的右子樹情況。

到此這篇關於C++二元樹的前序中序後序非遞迴實現方法詳細講解的文章就介紹到這了,更多相關C++二元樹的前序中序後序實現內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com