二叉樹的遍歷與構造

唉,好想回家,我想回家跟饅頭醬玩,想老爸老媽。如果上天再給我一次選擇的機會,我會選擇當一只小動物,或者當棵大樹也好,或者我希望自己不要有那么多多余的情緒,不要太被別人影響,開心點,想睡就睡,想玩就玩,不要為難自己。老爸每次都和我說累了就回家,但越是這樣我就越希望自己變得更強大一點。希望明天是個好天氣。

目錄

一、遍歷

1 前序遍歷

(1)遞歸

(2)非遞歸(先右后左哈)

2 中序遍歷

(1)遞歸

(2)非遞歸

3 后序遍歷

(1)遞歸

(2)非遞歸(中右左,反轉列表后變成左右中)

4 層序遍歷

(1)bfs(借助隊列)

(2)dfs

二、構造

1 構建最大二叉樹

2 由 前 中 構造

3 由 前?后 構造

4 由?中 后 構造


一、遍歷

1 前序遍歷

(1)遞歸

   private static void preorderHelper(TreeNode node, List<Integer> result) {if (node == null) return;result.add(node.val);preorderHelper(node.left, result);preorderHelper(node.right, result);}

(2)非遞歸(先右后左哈)

// 前序遍歷 - 非遞歸public static List<Integer> preorderTraversalIterative(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) return result;Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();result.add(node.val);if (node.right != null) stack.push(node.right);if (node.left != null) stack.push(node.left);}return result;}

2 中序遍歷

(1)遞歸

 private static void inorderHelper(TreeNode node, List<Integer> result) {if (node == null) return;inorderHelper(node.left, result);result.add(node.val);inorderHelper(node.right, result);}

(2)非遞歸

核心思路是先將當前節點及其所有左子節點依次入棧,直到左子節點為空,接著從棧中彈出節點進行訪問,然后將當前節點更新為彈出節點的右子節點,繼續重復上述操作。

// 中序遍歷 - 非遞歸public static List<Integer> inorderTraversalIterative(TreeNode root) {List<Integer> result = new ArrayList<>();Stack<TreeNode> stack = new Stack<>();TreeNode current = root;while (current != null || !stack.isEmpty()) {while (current != null) {stack.push(current);current = current.left;}current = stack.pop();result.add(current.val);current = current.right;}return result;}

3 后序遍歷

(1)遞歸

private static void postorderHelper(TreeNode node, List<Integer> result) {if (node == null) return;postorderHelper(node.left, result);postorderHelper(node.right, result);result.add(node.val);}

(2)非遞歸(中右左,反轉列表后變成左右中)

 // 后序遍歷 - 非遞歸public static List<Integer> postorderTraversalIterative(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null) return result;Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();result.add(node.val);if (node.left != null) stack.add(node.left);if (node.right != null) stack.add(node.right);}Collections.reverse(result);return result;}

4 層序遍歷

(1)bfs(借助隊列)

 // 層序遍歷 - BFS(借助隊列)public static List<List<Integer>> levelOrderTraversalBFS(TreeNode root) {List<List<Integer>> result = new ArrayList<>();if (root == null) return result;Queue<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()) {int levelSize = queue.size();List<Integer> level = new ArrayList<>();for (int i = 0; i < levelSize; i++) {TreeNode node = queue.poll();level.add(node.val);if (node.left != null) queue.offer(node.left);if (node.right != null) queue.offer(node.right);}result.add(level);}return result;}

(2)dfs

 // 層序遍歷 - DFSpublic static List<List<Integer>> levelOrderTraversalDFS(TreeNode root) {List<List<Integer>> result = new ArrayList<>();dfs(root, 0, result);return result;}private static void dfs(TreeNode node, int level, List<List<Integer>> result) {if (node == null) return;if (level >= result.size()) {result.add(new ArrayList<>());}result.get(level).add(node.val);dfs(node.left, level + 1, result);dfs(node.right, level + 1, result);}

二、構造

1 構建最大二叉樹

給定一個不重復的整數數組 nums 。 最大二叉樹 可以用下面的算法從 nums 遞歸地構建:

創建一個根節點,其值為 nums 中的最大值。
遞歸地在最大值 左邊 的 子數組前綴上 構建左子樹。
遞歸地在最大值 右邊 的 子數組后綴上 構建右子樹。
返回 nums 構建的 最大二叉樹

輸入:nums = [3,2,1,6,0,5]
輸出:[6,3,5,null,2,0,null,null,1]
解釋:遞歸調用如下所示:

[3,2,1,6,0,5] 中的最大值是 6 ,左邊部分是 [3,2,1] ,右邊部分是 [0,5] 。
[3,2,1] 中的最大值是 3 ,左邊部分是 [] ,右邊部分是 [2,1] 。
空數組,無子節點。
[2,1] 中的最大值是 2 ,左邊部分是 [] ,右邊部分是 [1] 。
空數組,無子節點。
只有一個元素,所以子節點是一個值為 1 的節點。
[0,5] 中的最大值是 5 ,左邊部分是 [0] ,右邊部分是 [] 。
只有一個元素,所以子節點是一個值為 0 的節點。
空數組,無子節點。


解法&思路

首先要解決的是找到每次遞歸傳入數組的最大值做為根節點
該最大值下標左邊的元素遞歸構造為左子樹,右邊的元素遞歸構造為右子樹

// 定義二叉樹節點類
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val = val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}class Solution {public TreeNode constructMaximumBinaryTree(int[] nums) {return build(nums, 0, nums.length);}private TreeNode build(int[] nums, int start, int end) {// 如果數組為空,返回 nullif (start == end) {return null;}// 找到最大值和最大值的索引int maxIndex = start;for (int i = start + 1; i < end; i++) {if (nums[i] > nums[maxIndex]) {maxIndex = i;}}// 用最大值創建根節點TreeNode rootNode = new TreeNode(nums[maxIndex]);// 最大值左側為左子樹rootNode.left = build(nums, start, maxIndex);// 最大值右側為右子樹rootNode.right = build(nums, maxIndex + 1, end);return rootNode;}
}

2 由 前 中 構造

// 定義二叉樹節點類
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val = val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}class Solution {public TreeNode buildTree(int[] preorder, int[] inorder) {return build(preorder, inorder, 0, 0, inorder.length - 1);}private TreeNode build(int[] preorder, int[] inorder, int preStart, int inStart, int inEnd) {// 如果中序遍歷的起始下標大于結束下標,說明當前子樹為空if (inStart > inEnd) {return null;}// 從前序遍歷中找到根節點int rootVal = preorder[preStart];TreeNode rootNode = new TreeNode(rootVal);// 在中序遍歷中找到根節點的位置int rootIndex = -1;for (int i = inStart; i <= inEnd; i++) {if (inorder[i] == rootVal) {rootIndex = i;break;}}// 計算左子樹的大小int leftSize = rootIndex - inStart;// 遞歸構造左子樹// 左子樹的前序遍歷范圍:preStart + 1 到 preStart + leftSize// 左子樹的中序遍歷范圍:inStart 到 rootIndex - 1rootNode.left = build(preorder, inorder, preStart + 1, inStart, rootIndex - 1);// 遞歸構造右子樹// 右子樹的前序遍歷范圍:preStart + leftSize + 1 到 preStart + leftSize + 右子樹大小// 右子樹的中序遍歷范圍:rootIndex + 1 到 inEndrootNode.right = build(preorder, inorder, preStart + leftSize + 1, rootIndex + 1, inEnd);return rootNode;}
}

至于為什么只需要中序遍歷的終點,而不需要前序遍歷的終點?因為在我們的思路中其實可以發現只需要前序遍歷的起點確認根節點的值,并不需要終點值。我們可以隨便選擇一個遍歷的終點值用來確認邊界值,即這部分代碼。

if(inStart > inEnd){return null
}

3 由 前?后 構造

// 定義二叉樹節點類
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val = val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}class Solution {public TreeNode constructFromPrePost(int[] preorder, int[] postorder) {return build(preorder, 0, preorder.length - 1, postorder, 0, postorder.length - 1);}private TreeNode build(int[] preorder, int preStart, int preEnd, int[] postorder, int postStart, int postEnd) {// 如果前序遍歷的起始下標大于結束下標,說明當前子樹為空if (preStart > preEnd) {return null;}// 當前子樹只有一個節點時,直接返回該節點if (preStart == preEnd) {return new TreeNode(preorder[preStart]);}// 找到根節點int rootVal = preorder[preStart];TreeNode root = new TreeNode(rootVal);// 找到左子樹起點在后序遍歷中的位置int leftStartIndex = -1;for (int i = postStart; i <= postEnd; i++) {if (postorder[i] == preorder[preStart + 1]) {leftStartIndex = i;break;}}// 計算左子樹的長度int size = leftStartIndex - postStart + 1;// 遞歸構造左子樹// 左子樹的前序范圍:preStart + 1 到 preStart + size// 左子樹的后序范圍:postStart 到 leftStartIndexroot.left = build(preorder, preStart + 1, preStart + size, postorder, postStart, leftStartIndex);// 遞歸構造右子樹// 右子樹的前序范圍:preStart + size + 1 到 preEnd// 右子樹的后序范圍:leftStartIndex + 1 到 postEnd - 1root.right = build(preorder, preStart + size + 1, preEnd, postorder, leftStartIndex + 1, postEnd - 1);return root;}
}

4 由?中 后 構造

// 定義二叉樹節點類
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val = val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}class Solution {public TreeNode buildTree(int[] inorder, int[] postorder) {return build(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1);}private TreeNode build(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) {// 如果中序遍歷的起始下標大于結束下標,說明當前子樹為空if (inStart > inEnd) {return null;}// 后序遍歷的最后一個節點是根節點int rootVal = postorder[postEnd];TreeNode rootNode = new TreeNode(rootVal);// 找到根節點在中序遍歷中的位置int rootIndex = -1;for (int i = inStart; i <= inEnd; i++) {if (inorder[i] == rootVal) {rootIndex = i;break;}}// 計算左子樹的大小int leftSize = rootIndex - inStart;// 遞歸構造左子樹// 左子樹的中序范圍:inStart 到 rootIndex - 1// 左子樹的后序范圍:postStart 到 postStart + leftSize - 1rootNode.left = build(inorder, inStart, rootIndex - 1, postorder, postStart, postStart + leftSize - 1);// 遞歸構造右子樹// 右子樹的中序范圍:rootIndex + 1 到 inEnd// 右子樹的后序范圍:postStart + leftSize 到 postEnd - 1rootNode.right = build(inorder, rootIndex + 1, inEnd, postorder, postStart + leftSize, postEnd - 1);return rootNode;}
}

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

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

相關文章

leetcode 141. Linked List Cycle

題目描述&#xff1a; 代碼&#xff1a; 用哈希表也可以解決&#xff0c;但真正考察的是用快慢指針法。 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Soluti…

AI輔助DevOps與自動化測試:重構軟件工程效率邊界

隨著AI技術滲透至軟件開發生命周期&#xff0c;DevOps與自動化測試領域正經歷顛覆性變革。本文系統性解析AI在需求分析、測試用例生成、部署決策、異常檢測等環節的技術實現路徑&#xff0c;結合微軟Azure DevOps、Tesla自動駕駛測試等典型場景&#xff0c;探討AI如何突破傳統效…

5月7號.

flex布局: 表單標簽: 表單標簽-表單項:

【AI面試準備】中文分詞與實體抽取技術詳解

分詞&#xff0c;詞性標準 目錄 一、分詞與詞性標注1. **分詞&#xff08;Word Segmentation&#xff09;**2. **詞性標注&#xff08;Part-of-Speech Tagging&#xff09;** 二、實體抽取&#xff08;Named Entity Recognition, NER&#xff09;1. **實體類型示例**2. **輸出…

【AI落地應用實戰】Amazon Bedrock 零門檻使用 DeepSeek-R1:在 Amazon Bedrock 上部署與調用的完整實踐指南

隨著大語言模型&#xff08;LLM&#xff09;技術的快速發展&#xff0c;企業和開發者對具備更強理解與生成能力的模型需求也愈加旺盛。DeepSeek-R1 作為 DeepSeek 公司推出的一款強大開源模型&#xff0c;不僅在多項評測中表現優異&#xff0c;更具備出色的推理能力和長文本處理…

阿里云平臺與STM32的物聯網設計

基于阿里云平臺與STM32的物聯網設計方案可結合硬件選型、通信協議、云端配置及功能實現等多個維度進行設計。以下是綜合多個參考案例的詳細設計方案&#xff1a; 一、硬件選型與架構設計 主控芯片選擇 STM32系列&#xff1a;推薦使用STM32F103&#xff08;如STM32F103ZET6、STM…

IBM BAW(原BPM升級版)使用教程Toolkit介紹

本部分為“IBM BAW&#xff08;原BPM升級版&#xff09;使用教程系列”內容的補充。 一、系統Toolkit 在 IBM Business Automation Workflow (BAW) 中&#xff0c;System Toolkit 是一組預先定義和配置好的工具、功能和組件&#xff0c;旨在幫助流程設計者和開發人員快速構建…

力扣-hot100 (矩陣置零)

73. 矩陣置零 中等 給定一個 *m* x *n* 的矩陣&#xff0c;如果一個元素為 0 &#xff0c;則將其所在行和列的所有元素都設為 0 。請使用 原地 算法。 示例 1&#xff1a; 輸入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 輸出&#xff1a;[[1,0,1],[0,0,0],[1,0,1]] 示…

安裝并運行第一個Spark程序

安裝并運行第一個Spark程序需要完成以下步驟&#xff1a;安裝Java和Spark&#xff0c;配置環境變量&#xff0c;編寫并運行Spark程序。以下是詳細的教程&#xff1a; 1. 安裝Java Spark需要Java運行環境&#xff08;JRE&#xff09;或Java開發工具包&#xff08;JDK&#xff…

Python Selenium爬蟲功能使用介紹

本文介紹python selenium 爬蟲的功能以及使用 1. 基礎核心功能 瀏覽器控制 from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager# 自動管理瀏覽器驅動 driver webdriver.Chro…

Cloudera CDP 7.1.3 主機異常關機導致元數據丟失,node不能與CM通信

問題描述 plaintext ERROR Could not load post-deployment data from /var/run/cloudera-scm-agent/process/ccdeploy_hadoop-conf_etchadoopconf.cloudera.yarn_-8903374259073700469 IOError: [Errno 2] No such file or directory: /var/run/cloudera-scm-agent/proce…

Nginx安全防護與HTTPS部署

目錄 Nginx 隱藏版本號 限制危險請求方法 請求限制&#xff08;CC攻擊防御&#xff09; 壓力測試 防盜鏈 防止防盜鏈 動態黑名單 自動添加黑名單 HTTPS配置 HTTPS 概念 安全通信的四大原則 HTTPS的幾種加密方式 nginx https的作用 Nginx 隱藏版本號 &#xff01;&#xff01;&a…

C++類對象的隱式類型轉換和編譯器返回值優化

文章目錄 前言1. 隱式類型轉換1.1 單參數的隱式類型轉換1.2 多參數的隱式類型轉換1.3 explicit關鍵字 2. 編譯器的優化2.1 普通構造優化2.2 函數傳參優化2.3 函數返回優化 前言 在類與對象的學習過程中&#xff0c;一定會對隱式類型轉換這個詞不陌生。對于內置類型而言&#x…

領麥微紅外溫度傳感器,搖奶器測溫應用

在育兒領域&#xff0c;精準控制奶液溫度是守護寶寶健康的重要環節。領麥微作為MEMS傳感器領域的創新先鋒&#xff0c;通過其紅外測溫傳感器的非接觸式測量、高精度測溫、實時反饋以及智能溫控節能等核心優勢&#xff0c;為搖奶器注入了全新的智能化解決方案。這一技術不僅提升…

第十一屆藍橋杯 2020 C/C++組 蛇形填數

目錄 題目&#xff1a; 題目描述: 題目鏈接&#xff1a; 思路&#xff1a; 思路詳解&#xff1a; 代碼&#xff1a; 代碼詳解&#xff1a; 題目&#xff1a; 題目描述: 題目鏈接&#xff1a; 蛇形填數 - 藍橋云課 思路&#xff1a; 思路詳解&#xff1a; 看圖找規律…

如何檢查 Watchtower 是否正常工作及更新未生效的排查方法【日常排錯】

文章目錄 前言一、驗證 Watchtower 是否正在運行1. 檢查 Watchtower 容器狀態2. 查看 Watchtower 日志 二、檢查5分鐘間隔設置是否正確1. 確認啟動命令2. 驗證環境變量 三、排查更新未生效的原因1. 檢查是否有鏡像更新2. 檢查容器標簽3. 檢查監控范圍 四、測試 Watchtower 功能…

寶塔面板,刪除項目后還能通過域名進行訪問

場景&#xff1a;在阿里云寶塔面板中&#xff0c;刪除了之前建立的html項目&#xff0c;通過之前綁定的域名還是可以訪問&#xff0c;又把項目的目錄文件刪除&#xff0c;發現還是不行 又清理了瀏覽器緩存&#xff0c;但還是有這個問題通過該域名重新創建一個html項目&#xff…

多層PCB SMT貼裝全流程指南:從物料準備到回流焊工藝控制

在電子制造領域&#xff0c;多層PCB板元器件貼片是一項重要的技術操作。本文將詳細介紹多層PCB板元器件貼片的操作流程和注意事項&#xff0c;幫助您更好地理解和掌握這項技術。 一、準備階段 在進行多層PCB板元器件貼片操作前&#xff0c;需要做好以下準備工作&#xff1a; 1.…

PAT(最近)

1022 D進制的AB - PAT (Basic Level) Practice &#xff08;中文&#xff09; 加減位置調換 本來以為就是簡單的 十進制轉換為一個長的字符串 沒想到在那個拼接字符串的時候 只需要簡單的 加減位置調換就可以 避免使用麻煩的翻轉函數 import java.util.Scanner; public clas…

【Harbor v2.13.0 詳細安裝步驟 安裝證書啟用 HTTPS】

Harbor v2.13.0 詳細安裝步驟&#xff08;啟用 HTTPS&#xff09; 1. 環境準備 系統要求&#xff1a;至少 4GB 內存&#xff0c;100GB 磁盤空間。 已安裝組件&#xff1a; Docker&#xff08;版本 ≥ 20.10&#xff09;Docker Compose&#xff08;版本 ≥ v2.0&#xff09; 域…