代碼隨想錄算法訓練營day14|二叉樹的遞歸遍歷、二叉樹的迭代遍歷、二叉樹的統一迭代法

二叉樹的遞歸遍歷

首先需要明確的一點是,前序中序和后序在二叉樹的遞歸遍歷中的區別僅在于遞歸函數中操作的順序,前序是在遍歷一個節點的左右子樹前進行操作,中序是在遍歷一個節點的左子樹后進行操作再遍歷右子樹,而后序是在遍歷完左右子樹再進行操作。所以在遞歸函數中,僅是順序的差別。前序中序和后序可簡化為中左右、左中右和左右中,此外,寫遞歸函數時,需要明確三點:

  • 確定遞歸函數的參數和返回值
  • 確定終止條件
  • 確定單層遞歸的邏輯

? ? ? ? 在對二叉樹的遞歸遍歷中,遞歸函數需要傳入樹節點TreeNode * cur和vec數組進行操作,無實際返回值,所以函數為void,當遞歸操作時,若節點為空則返回,對每層遞歸的邏輯以前序遍歷來說,先講當前節點的val值傳入數組vec中,之后遍歷左子樹,再之后遍歷右子樹。

代碼隨想錄 (programmercarl.com)二叉樹的遞歸遍歷icon-default.png?t=N7T8https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%80%92%E5%BD%92%E9%81%8D%E5%8E%86.html#%E6%80%9D%E8%B7%AF看到遞歸就暈?帶你理解遞歸的本質!_嗶哩嗶哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1UD4y1Y769/?spm_id_from=333.880.my_history.page.click&vd_source=fc4a6e70e3a87b7ea67c2024e326e7c5

前序遍歷遞歸函數如下所示,

void traversal(TreeNode * cur, vector<int> & vec){//創建前序遞歸遍歷函數if(cur == nullptr)//當當前遍歷節點為空時,返回return;vec.push_back(cur->val);//中 將當前遍歷節點的val值存入vec數組 *操作traversal(cur->left,vec);//遍歷左子樹traversal(cur->right,vec);//遍歷右子樹}void traversal(TreeNode * cur, vector<int> & vec){//創建中序遞歸遍歷函數if(cur == nullptr)//當當前遍歷節點為空時,返回return;traversal(cur->left,vec);//遍歷左子樹vec.push_back(cur->val);//中 將當前遍歷節點的val值存入vec數組 *操作traversal(cur->right,vec);//遍歷右子樹}void traversal(TreeNode * cur, vector<int> & vec){//創建后序遞歸遍歷函數if(cur == nullptr)//當當前遍歷節點為空時,返回return;traversal(cur->left,vec);//遍歷左子樹traversal(cur->right,vec);//遍歷右子樹vec.push_back(cur->val);//中 將當前遍歷節點的val值存入vec數組 *操作}

對于主函數體,只需傳入節點,在函數體中創建一個ans數組,并傳入traversal函數中。

vector<int> preorderTraversal(TreeNode* root) {vector<int> ans;traversal(root,ans);return ans;}

遞歸遍歷樹節點的時間復雜度和空間復雜度均為O(n)。

二叉樹的迭代遍歷

前序遍歷

? ? ? ? 考慮前序遞歸遍歷的過程,若操作為打印,則先將自身val值打印后,對所有左子樹打印,然后打印右子樹,考慮使用棧來模擬前序遍歷的過程(也是用棧來模擬遞歸的過程),由于棧是先入后出的數據結構,前序遍歷結果左子樹節點在右子樹節點前,所以需先對右子樹中節點入棧,再對左子樹中節點入棧。然后是大致流程,創建結果數組ans,先判斷根節點是否為空,若為空直接返回結果數組,否則將根節點入棧,在一個while循環中實現二叉樹的迭代前序遍歷,由于棧模擬的遞歸過程,當棧為空時,也就意味著遞歸結束,即我們遍歷結果結果結束。所以while的循環條件為stack.size()!=0,在循環體內,創建一個指針指向當前節點,將其val值加入ans數組,之后再彈出棧,(第一次循環的pop為根節點,即第一次前序遍歷要對根節點進行操作,之后因為我們是對棧是先加入右子樹節點后加入左子樹節點,所以會先對節點的左子樹進行操作后對節點的右子樹進行操作,完成前序遍歷的過程),之后判斷右子樹的存在,若存在,將其入棧,判斷左子樹的存在,存在則將其入棧,這就是循環體內內容。

class Solution {
public:vector<int> preorderTraversal(TreeNode* root) {stack<TreeNode*> stack;vector<int> ans;if(root == nullptr){//當根節點為nullptr,直接返回ansreturn ans;}stack.push(root);while(stack.size()!=0){//棧不為空則循環TreeNode*cur = stack.top();//創建cur指針指向棧頂地址ans.push_back(cur->val);//將棧頂地址的值存入ans數組stack.pop();//出棧if(cur->right)//判斷左右子樹存在的情況,若存在,將其存入棧中,注意順序,先右后左                //出棧則為先左后右stack.push(cur->right);if(cur->left)stack.push(cur->left);}return ans;}
};

該算法的時間復雜度和空間復雜度均為O(n)。

中序遍歷

? ? ? ? 在遍歷二叉樹的節點時,創建遍歷指針cur,先遍歷左子樹,依次將所有左節點全部入棧,當當前節點的左節點為空時,彈出棧中元素給遍歷指針cur,并將cur指向的val傳入數組中,完成中的操作,令cur = cur->right,并繼續進行循環。算法的時間和空間復雜度均為O(n)。

class Solution {
public:// 定義一個函數,用于執行中序遍歷vector<int> inorderTraversal(TreeNode* root) {// 創建一個空向量 ans,用于存儲遍歷的結果vector<int> ans;// 創建一個空棧 st,用于輔助遍歷stack<TreeNode*> st;// 創建一個指針 cur,初始指向根節點TreeNode* cur = root;// 當 cur 指向的節點不為空或者棧 st 不為空時,進行循環while (cur != nullptr || !st.empty()) {// 如果 cur 指向的節點不為空,則將其壓入棧 st 中,并移動 cur 指針到其左子節點if (cur != nullptr) {st.push(cur);cur = cur->left;}// 如果 cur 指向的節點為空,說明左子節點已經訪問完畢,此時從棧 st 中彈出最上面的節點else {cur = st.top(); // 獲取棧頂節點st.pop(); // 彈出棧頂節點// 將彈出的節點的值添加到 ans 向量中ans.push_back(cur->val);// 移動 cur 指針到其右子節點cur = cur->right;}}// 循環結束后,返回存儲遍歷結果的 ans 向量return ans;}
};

后序遍歷

????????考慮前序遍歷和后序遍歷的相似之處,調整一下前序遍歷中左右節點的入棧順序,讓中左右變為中右左,之后再通過一個reverse即能實現后序遍歷。

調整

//前序
if(cur->right)//判斷左右子樹存在的情況,若存在,將其存入棧中,注意順序,先右后左                //出棧則為先左后右
stack.push(cur->right);
if(cur->left)
stack.push(cur->left);//后序
if(cur->left)
stack.push(cur->left);
if(cur->right)
stack.push(cur->right);

整體代碼

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {stack<TreeNode*> stack;vector<int> ans;if(root == nullptr){//當根節點為nullptr,直接返回ansreturn ans;}stack.push(root);while(stack.size()!=0){//棧不為空則循環TreeNode*cur = stack.top();//創建cur指針指向棧頂地址ans.push_back(cur->val);//將棧頂地址的值存入ans數組stack.pop();//出棧if(cur->left)stack.push(cur->left);if(cur->right)stack.push(cur->right);}reverse(ans.begin(),ans.end());//反轉return ans;}
};

二叉樹的統一迭代法

周末再看看

代碼隨想錄 (programmercarl.com)二叉樹的統一迭代法icon-default.png?t=N7T8https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E7%BB%9F%E4%B8%80%E8%BF%AD%E4%BB%A3%E6%B3%95.html#%E6%80%9D%E8%B7%AF

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18097.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18097.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18097.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++算術運算和自增自減運算

一 引言 表示運算的符號稱為運算符。 算術運算&#xff1b; 比較運算&#xff1b; 邏輯運算&#xff1b; 位運算&#xff1b; 1 算術運算 算術運算包括加、減、乘、除、乘方、指數、對數、三角函數、求余函數&#xff0c;這些都是算術運算。 C中用、-、*、/、%分別表示加、減…

【AI】AI框架項目OpenWebUI如何追加模型

【背景】 openWebUI是一個非常好用的AI框架項目&#xff0c;既可以用API形式連接各類外部AI模型&#xff0c;也可以直接連接服務器硬盤上部署的離線大模型。 簡單來說&#xff0c;OpenWebUI可以用來方便地把你的本地模型變為可供所有內網人員使用的SAAS服務站點&#xff0c;并…

《當微服務遇上Ribbon:一場負載均衡的華麗舞會》

在微服務的廚房里&#xff0c;如何確保每一道服務都恰到好處&#xff1f;揭秘Spring Cloud Ribbon如何像大廚一樣精心調配資源&#xff0c;讓負載均衡變得像烹飪藝術一樣簡單&#xff01; 文章目錄 Spring Cloud Ribbon 詳解1. 引言微服務架構中的負載均衡需求Spring Cloud Rib…

【算法實戰】每日一題:設計一個算法,用最少數量的矩形覆蓋一系列寬度為d、高度為w的矩形,且使用矩形不能超出邊界

題目 設計一個算法&#xff0c;用最少數量的矩形覆蓋一系列寬度為d、高度為w的矩形建筑物側墻&#xff0c;且矩形不能超出邊界。 核心思路 考慮這種結構 前面遞增后面一個與前面的某個高度一致&#xff0c;這時候考慮最下面的覆蓋&#xff08;即都是從最下面向上覆蓋&#…

redis數據類型set,zset

華子目錄 Set結構圖相關命令sdiff key1 [key2]sdiffstore destination key1 [key2...]sinter key1 [key2...]sinterstore destination key1 [key2...]sunion key1 [key2...]sunionstore destination key1 [key2...]smove source destination memberspop key [count]sscan key c…

Java GC問題排查的一些個人總結和問題復盤

個人博客 Java GC問題排查的一些個人總結和問題復盤 | iwts’s blog 是否存在GC問題判斷指標 有的比較明顯&#xff0c;比如發布上線后內存直接就起飛了&#xff0c;這種也是比較好排查的&#xff0c;也是最多的。如果單純從優化角度&#xff0c;看當前應用是否需要優化&…

探索旅行的優惠之選,千益暢行旅游卡讓旅程更省心省力!

在旅行的道路上&#xff0c;一張旅游卡往往能為您帶來意想不到的便利與優惠。那么&#xff0c;對于千益暢行旅游卡&#xff0c;您是否好奇如何輕松擁有它呢&#xff1f; 首先&#xff0c;千益暢行旅游卡作為旅行者的貼心伴侶&#xff0c;為您提供了多樣化的獲取渠道。您可以通…

Unity實現首行縮進兩個字符

效果 在Unity中如果想實現首行縮進兩個字符&#xff0c;你會發現按空格是沒法實現的。 實現原理&#xff1a;用空白的透明的字替代原來的位置。 代碼&#xff1a; <color#FFFFFF00>XXX</color> 趕緊去試試吧&#xff01;

備戰秋招—模擬版圖面試題來了

隨著暑期的腳步逐漸臨近&#xff0c;電子工程和集成電路設計領域的畢業生們&#xff0c;也將迎來了另一個求職的黃金期——秋招。我們總說機會是留給有準備的人。對于有志于投身于模擬版圖設計的學子們來說&#xff0c;為了在眾多求職者中脫穎而出&#xff0c;充分備戰模擬版圖…

C# 工商銀行缺少infosecapiLib.infosec

搜索Tlbimp.exe 這里使用4.8.1下的處理&#xff0c;以管理員身份打開powershell cd "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8.1 Tools".\TlbImp.exe "G:\CSharp\icbc-api-sdk-cop-c#\sdk-cop\sdk-cop\dll\infosecapi.dll" …

PCIe協議之-DLLP詳解

?前言&#xff1a; &#x1f31f;數據鏈路層的功能 數據鏈路層將從物理層中獲得報文&#xff0c; 并將其傳遞給事務層&#xff1b; 同時接收事務層的報文&#xff0c; 并將其轉發到物理層; 核心的功能有以下三點 1.保證TLP在 PCIe 鏈路中的正確傳遞; 2.數據鏈路層使用了容錯…

頁面導出PDF,非可視區域如何解決

const exportToPDF () > {const element document.getElementById(chart-container);if (!element) return;const originalScrollHeight element.scrollHeight;// 臨時解除滾動條限制&#xff0c;確保所有內容都可見element.style.height ${originalScrollHeight}px;// …

殺死那個進程

一、場景 eclipse在啟動tomcat時&#xff0c;出現端口被占用的情況。我尋思著“任務管理器”沒出現相應程序在跑啊。 1.1問題&#xff1a;端口和進程的關系 端口和進程之間存在著一種關系&#xff0c;端口是一個邏輯概念&#xff0c;它用于標識網絡通信中的一個終點&#xff0…

SEC突發:以太坊ETF大概率獲批

美國證監會大概率批準以太坊現貨ETF。 5月20日&#xff0c;據外媒CoinDesk報道&#xff0c;知情人士透露&#xff0c;美國SEC周一要求證券交易所更新以太坊現貨ETF的19b-4備案文件。19b-4備案文件是一種表格&#xff0c;用于向SEC通報允許基金在交易所交易的規則變更。 三位消息…

利用cherry pick巧妙地將某次提交單獨合并到其他分支

0. 引言 最近在進行系統的多版本并行開發&#xff0c;涉及一些共有基礎功能提交時就遇到了麻煩&#xff0c;一份代碼需要向多個版本分支進行同步&#xff0c;以保證多版本都能有更新該基礎功能。 多次對比提交的方式顯然會帶來巨大的工作量。但實際上我們可以通過git的cherry…

「Python Socket超能力:網絡世界的隱形斗篷!」

Hi&#xff0c;我是阿佑&#xff0c;今天將帶領大家揭開Python Socket編程的神秘面紗&#xff0c;賦予我們的網絡應用隱形斗篷般的超能力&#xff01; 深入探討Socket編程的革命性力量&#xff0c;教你如何用Python的Socket模塊來構建強大的網絡應用。從簡單的HTTP服務器到復雜…

MagicLens:新一代圖像搜索技術和產品形態

MagicLens&#xff1a;Self-Supervised Image Retrieval with Open-Ended Instructions MagicLens: 自監督圖像檢索與開放式指令 作者&#xff1a;Kai Zhang&#xff0c; Yi Luan&#xff0c; Hexiang Hu&#xff0c; Kenton Lee&#xff0c; Siyuan Qiao&#xff0c; Wenhu …

Selenium操作瀏覽器Cookie(增/刪/查看cookie)

天行健&#xff0c;君子以自強不息&#xff1b;地勢坤&#xff0c;君子以厚德載物。 每個人都有惰性&#xff0c;但不斷學習是好好生活的根本&#xff0c;共勉&#xff01; 文章均為學習整理筆記&#xff0c;分享記錄為主&#xff0c;如有錯誤請指正&#xff0c;共同學習進步。…

更新.gitmodules的子模塊倉庫地址,但是沒有生效,需要運行命令

當你更新了 .gitmodules 文件中的子模塊倉庫地址后&#xff0c;為了使這些更改生效并同步到實際的子模塊目錄&#xff0c;你需要執行以下步驟&#xff1a; 同步.gitmodules的更改&#xff1a; 使用 git submodule sync 命令來同步.gitmodules文件中的URL修改到你的本地配置。執…

在VS Code中進行Java的單元測試

在VS Code中可以使用 Test Runner for Java擴展進行Java的測試執行和調試。 Test Runner for Java的功能 Test Runner for Java 結合 Language Support for Java by Red Hat 和 Debugger for Java這兩個插件提供如下功能&#xff1a; 運行測試&#xff1a; Test Runner for …