最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++實現(xiàn)LeetCode(145.二叉樹的后序遍歷)

 更新時間:2021年07月19日 16:50:45   作者:Grandyang  
這篇文章主要介紹了C++實現(xiàn)LeetCode(145.二叉樹的后序遍歷),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下

[LeetCode] 145. Binary Tree Postorder Traversal 二叉樹的后序遍歷

Given a binary tree, return the postorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},

   1
\
2
/
3

return [3,2,1].

Note: Recursive solution is trivial, could you do it iteratively?

經(jīng)典題目,求二叉樹的后序遍歷的非遞歸方法,跟前序,中序,層序一樣都需要用到棧,后序的順序是左-右-根,所以當一個結點值被取出來時,它的左右子結點要么不存在,要么已經(jīng)被訪問過了。先將根結點壓入棧,然后定義一個輔助結點 head,while 循環(huán)的條件是棧不為空,在循環(huán)中,首先將棧頂結點t取出來,如果棧頂結點沒有左右子結點,或者其左子結點是 head,或者其右子結點是 head 的情況下。將棧頂結點值加入結果 res 中,并將棧頂元素移出棧,然后將 head 指向棧頂元素;否則的話就看如果右子結點不為空,將其加入棧,再看左子結點不為空的話,就加入棧,注意這里先右后左的順序是因為棧的后入先出的特點,可以使得左子結點先被處理。下面來看為什么是這三個條件呢,首先如果棧頂元素如果沒有左右子結點的話,說明其是葉結點,而且入棧順序保證了左子結點先被處理,所以此時的結點值就可以直接加入結果 res 了,然后移出棧,將 head 指向這個葉結點,這樣的話 head 每次就是指向前一個處理過并且加入結果 res 的結點,那么如果棧頂結點的左子結點或者右子結點是 head 的話,說明其子結點已經(jīng)加入結果 res 了,那么就可以處理當前結點了。

看到這里,大家可能對 head 的作用,以及為何要初始化為 root,還不是很清楚,這里再解釋一下。head 是指向上一個被遍歷完成的結點,由于后序遍歷的順序是左-右-根,所以一定會一直將結點壓入棧,一直到把最左子結點(或是最左子結點的最右子結點)壓入棧后,開始進行處理。一旦開始處理了,head 就會被重新賦值。所以 head 初始化值并沒有太大的影響,唯一要注意的是不能初始化為空,因為在判斷是否打印出當前結點時除了判斷是否是葉結點,還要看 head 是否指向其左右子結點,如果 head 指向左子結點,那么右子結點一定為空,因為入棧順序是根-右-左,不存在右子結點還沒處理,就直接去處理根結點了的情況。若 head 指向右子結點,則是正常的左-右-根的處理順序。那么回過頭來在看,若 head 初始化為空,且此時正好左子結點不存在,那么在壓入根結點時,head 和左子結點相等就成立了,此時就直接打印根結點了,明顯是錯的。所以 head 只要不初始化為空,一切都好說,甚至可以新建一個結點也沒問題。將 head 初始化為 root,也可以,就算只有一個 root 結點,那么在判定葉結點時就將 root 打印了,然后就跳出 while 循環(huán)了,也不會出錯。代碼如下:

解法一:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        if (!root) return {};
        vector<int> res;
        stack<TreeNode*> s{{root}};
        TreeNode *head = root;
        while (!s.empty()) {
            TreeNode *t = s.top();
            if ((!t->left && !t->right) || t->left == head || t->right == head) {
                res.push_back(t->val);
                s.pop();
                head = t;
            } else {
                if (t->right) s.push(t->right);
                if (t->left) s.push(t->left);
            }
        }
        return res;
    }
};

由于后序遍歷的順序是左-右-根,而先序遍歷的順序是根-左-右,二者其實還是很相近的,可以先在先序遍歷的方法上做些小改動,使其遍歷順序變?yōu)楦?右-左,然后翻轉一下,就是左-右-根啦,翻轉的方法我們使用反向Q,哦不,是反向加入結果 res,每次都在結果 res 的開頭加入結點值,而改變先序遍歷的順序就只要該遍歷一下入棧順序,先左后右,這樣出棧處理的時候就是先右后左啦,參見代碼如下:

解法二:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        if (!root) return {};
        vector<int> res;
        stack<TreeNode*> s{{root}};
        while (!s.empty()) {
            TreeNode *t = s.top(); s.pop();
            res.insert(res.begin(), t->val);
            if (t->left) s.push(t->left);
            if (t->right) s.push(t->right);
        }
        return res;
    }
};

那么在 Binary Tree Preorder Traversal 中的解法二也可以改動一下變成后序遍歷,改動的思路跟上面的解法一樣,都是先將先序遍歷的根-左-右順序變?yōu)楦?右-左,再翻轉變?yōu)楹笮虮闅v的左-右-根,翻轉還是改變結果 res 的加入順序,然后把更新輔助結點p的左右順序換一下即可,代碼如下:

解法三:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> res;
        stack<TreeNode*> s;
        TreeNode *p = root;
        while (!s.empty() || p) {
            if (p) {
                s.push(p);
                res.insert(res.begin(), p->val);
                p = p->right;
            } else {
                TreeNode *t = s.top(); s.pop();
                p = t->left;
            }
        }
        return res;
    }
};

論壇上還有一種雙棧的解法,其實本質上跟解法二沒什么區(qū)別,都是利用了改變先序遍歷的順序來實現(xiàn)后序遍歷的,參見代碼如下:

解法四:

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        if (!root) return {};
        vector<int> res;
        stack<TreeNode*> s1, s2;
        s1.push(root);
        while (!s1.empty()) {
            TreeNode *t = s1.top(); s1.pop();
            s2.push(t);
            if (t->left) s1.push(t->left);
            if (t->right) s1.push(t->right);
        }
        while (!s2.empty()) {
            res.push_back(s2.top()->val); s2.pop();
        }
        return res;
    }
};

到此這篇關于C++實現(xiàn)LeetCode(145.二叉樹的后序遍歷)的文章就介紹到這了,更多相關C++實現(xiàn)二叉樹的后序遍歷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C語言之整數(shù)劃分問題(遞歸法)實例代碼

    C語言之整數(shù)劃分問題(遞歸法)實例代碼

    這篇文章主要介紹了C語言之整數(shù)劃分問題(遞歸法)實例代碼的相關資料,需要的朋友可以參考下
    2017-02-02
  • C++的友元和內(nèi)部類你了解嗎

    C++的友元和內(nèi)部類你了解嗎

    這篇文章主要為大家介紹了C++的友元和內(nèi)部類,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • C語言實現(xiàn)推箱子代碼

    C語言實現(xiàn)推箱子代碼

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)推箱子代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • C++中std::find函數(shù)介紹和使用場景

    C++中std::find函數(shù)介紹和使用場景

    std::find函數(shù)是一個非常實用的通用查找算法,適用于各種場景,本文主要介紹了C++中std::find函數(shù)介紹和使用場景,具有一定的參考價值,感興趣的可以了解一下
    2024-02-02
  • C++常見異常處理原理及代碼示例解析

    C++常見異常處理原理及代碼示例解析

    這篇文章主要介紹了C++常見異常處理原理及代碼示例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07
  • C++迭代器介紹(iterator、const_iterator、reverse_interator、const_reverse_interator)

    C++迭代器介紹(iterator、const_iterator、reverse_interator、const_rev

    這篇文章主要介紹了C++迭代器介紹(iterator、const_iterator、reverse_interator、const_reverse_interator),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • 詳解C++中的萬能頭文件

    詳解C++中的萬能頭文件

    C++萬能頭文件它是一個包含了每一個標準庫的頭文件,接下來通過本文給大家介紹C++中的萬能頭文件及優(yōu)缺點,需要的朋友可以參考下
    2023-02-02
  • C++實現(xiàn)簡易萬年歷

    C++實現(xiàn)簡易萬年歷

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡易萬年歷,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • C語言計算分段函數(shù)問題

    C語言計算分段函數(shù)問題

    這篇文章主要介紹了C語言計算分段函數(shù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 使用C語言來畫出皮卡丘的教程(附代碼)

    使用C語言來畫出皮卡丘的教程(附代碼)

    在C語言中使用圖形庫畫圖需要引入graphics.h庫,我們可以通過代碼實現(xiàn)畫出一個可愛的皮卡丘,將皮卡丘的繪制分為以下部分:耳朵、臉部、眼睛、嘴巴、手臂、腿部、尾巴,下面我們就來學習如何使用C語言編寫畫皮卡丘的代碼
    2024-01-01

最新評論

固原市| 张家港市| 武乡县| 克山县| 南郑县| 内黄县| 潼南县| 顺义区| 文成县| 丰城市| 通城县| 宜春市| 紫金县| 伊川县| 东阳市| 突泉县| 乌拉特前旗| 淮阳县| 微山县| 丹东市| 正蓝旗| 云南省| 宜君县| 保靖县| 依兰县| 读书| 镇雄县| 芦溪县| 闵行区| 泾川县| 咸宁市| 滦平县| 乌拉特后旗| 苏尼特左旗| 汉中市| 仪陇县| 宣化县| 怀远县| 天水市| 赣榆县| 灵璧县|