來說說二叉樹非遞歸遍歷

二叉樹的遍歷

早之前和同學聊天時,就提到了當時實習面試有一題就是要求非遞歸實現二叉樹遍歷,二叉樹本身就是一種通過遞歸定義的數據結構,所以用遞歸的方法遍歷二叉樹是很容易的,而二叉樹的遍歷又分爲前序遍歷,中序遍歷以及後序遍歷,其中非遞歸的算法前序遍歷和中序遍歷稍簡單,後序遍歷稍複雜,並且都要用到棧,下面算法以如下二叉樹爲例:
二叉樹
則算法遍歷的路線圖如下所示:

這裏寫圖片描述

前序遍歷

前序遍歷中,對於任一節點P可以看成根節點,它優先訪問根節點,然後訪問左孩子和右孩子。
對於P:
1. 訪問P,把P入棧;
2. 若P的左孩子不爲空,則使得P=P->left,回到操作1;
3. 若P的左孩子爲空,則P=棧頂元素,棧頂元素出棧,P=P->right;

以節點B爲例,則P=B,訪問B,然後把B入棧,使得P=D,然後訪問D並讓D入棧,因爲此時D的左孩子爲空,則表示已到達最左的節點,需要回退,則D出棧,使得P=D->right,又因爲D->right爲空,繼續回退,則B出棧,P=B->right,以此類推…

vector<int> preorderTraversal(TreeNode *root) {
        vector<int> res;
        stack<TreeNode *> s;
        TreeNode * p = root;
        while(p!=NULL||!s.empty())
        {
            while(p!=NULL)
            {
                res.push_back(p->val);
                s.push(p);
                p = p->left;
            }
            p = s.top();
            s.pop();
            p = p->right;
        }
        return res;
    }

中序遍歷

中序遍歷訪問節點的時機在從左孩子節點回退的時候,所以,
對於P:
1. 把P入棧;
2. 若P的左孩子不爲空,則使得P=P->left,回到操作1;
3. 若P的左孩子爲空,則P=棧頂元素,訪問P,棧頂元素出棧,P=P->right;

vector<int> inorderTraversal(TreeNode *root) {
        vector<int> res;
        stack<TreeNode *> s;
        TreeNode * p = root;
        while(p!=NULL||!s.empty())
        {
            while(p!=NULL)
            {
                s.push(p);
                p = p->left;
            }
            p = s.top();
            res.push_back(p->val);
            s.pop();
            p = p->right;

        }
        return res;
    }

後序遍歷

由遍歷的路線圖可知,對於任一節點有三個訪問時機,一次進入,兩次回退(左孩子回退和右孩子回退),對於前序遍歷,訪問時機在進入時,對於中序遍歷,訪問時機在第一次回退,即左孩子回退時,對於後序遍歷,訪問時機在第二次回退,即右孩子回退時。
也正因爲後序遍歷存在兩次回退,則需要加一個標誌位,表示是否是第二次回退。
有人可能會問爲什麼中序遍歷的第一次回退不需要加一個標誌位標示是否是第一次回退了,因爲這上面代碼中回退以後,把該節點從棧中pop了,所以在代碼中並不存在第二次回退。
對於P:
1. P的標誌位置true,P入棧;
2. 若P的左孩子不爲空,則使得P=P->left,P標誌位置true,回到操作1;
3. 若P的左孩子爲空,則P=棧頂元素,若P的標誌位爲true,則表示第一次回退,P標誌位置false,使P=P->right;若P的標誌位爲false,則表示第二次回退,P出棧,並訪問P;

vector<int> postorderTraversal(TreeNode *root) {
        vector<int> res;
        stack<pair<TreeNode *,int>>s;
        TreeNode *p = root;
        while(p!=NULL||!s.empty())
        {
            while(p)
            {
                s.push(pair<TreeNode*,int>(p,1));
                p = p->left;
            }
            pair<TreeNode*,int> q = s.top();
            s.pop();
            if(q.second==1)
            {
                s.push(pair<TreeNode*,int>(q.first,2));
                p = q.first->right;
            }
            else
            {
                res.push_back(q.first->val);
                p = NULL;
            }
        }
        return res;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章