# 0094. 二叉树的中序遍历 ## 题目地址(94. 二叉树的中序遍历) <https://leetcode-cn.com/problems/binary-tree-inorder-traversal/> ## 题目描述 ``` <pre class="calibre18">``` 给定一个二叉树,返回它的中序 遍历。 示例: 输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,3,2] 进阶: 递归算法很简单,你可以通过迭代算法完成吗? ``` ``` ## 前置知识 - 二叉树 - 递归 ## 公司 - 阿里 - 腾讯 - 百度 - 字节 ## 思路 递归的方式相对简单,非递归的方式借助栈这种数据结构实现起来会相对轻松。 如果采用非递归,可以用栈(Stack)的思路来处理问题。 中序遍历的顺序为左-根-右,具体算法为: - 从根节点开始,先将根节点压入栈 - 然后再将其所有左子结点压入栈,取出栈顶节点,保存节点值 - 再将当前指针移到其右子节点上,若存在右子节点,则在下次循环时又可将其所有左子结点压入栈中, 重复上步骤 ![](https://img.kancloud.cn/82/8c/828c1b13297bacd4c2b9276485b170d4_961x538.gif) (图片来自: <https://github.com/MisterBooo/LeetCodeAnimation>) ## 关键点解析 - 二叉树的基本操作(遍历)> 不同的遍历算法差异还是蛮大的 - 如果非递归的话利用栈来简化操作 - 如果数据规模不大的话,建议使用递归 - 递归的问题需要注意两点,一个是终止条件,一个如何缩小规模 - 终止条件,自然是当前这个元素是 null(链表也是一样) - 由于二叉树本身就是一个递归结构, 每次处理一个子树其实就是缩小了规模, 难点在于如何合并结果,这里的合并结果其实就是`left.concat(mid).concat(right)`, mid 是一个具体的节点,left 和 right`递归求出即可` ## 代码 - 语言支持:JS,C++,Python3, Java JavaScript Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * @param {TreeNode} root * @return {number[]} */</span> <span class="hljs-keyword">var</span> inorderTraversal = <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">root</span>) </span>{ <span class="hljs-title">// 1. Recursive solution</span> <span class="hljs-title">// if (!root) return [];</span> <span class="hljs-title">// const left = root.left ? inorderTraversal(root.left) : [];</span> <span class="hljs-title">// const right = root.right ? inorderTraversal(root.right) : [];</span> <span class="hljs-title">// return left.concat([root.val]).concat(right);</span> <span class="hljs-title">// 2. iterative solutuon</span> <span class="hljs-keyword">if</span> (!root) <span class="hljs-keyword">return</span> []; <span class="hljs-keyword">const</span> stack = [root]; <span class="hljs-keyword">const</span> ret = []; <span class="hljs-keyword">let</span> left = root.left; <span class="hljs-keyword">let</span> item = <span class="hljs-params">null</span>; <span class="hljs-title">// stack 中弹出的当前项</span> <span class="hljs-keyword">while</span> (left) { stack.push(left); left = left.left; } <span class="hljs-keyword">while</span> ((item = stack.pop())) { ret.push(item.val); <span class="hljs-keyword">let</span> t = item.right; <span class="hljs-keyword">while</span> (t) { stack.push(t); t = t.left; } } <span class="hljs-keyword">return</span> ret; }; ``` ``` C++ Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */</span> <span class="hljs-keyword">class</span> Solution { <span class="hljs-keyword">public</span>: <span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>> inorderTraversal(TreeNode* root) { <span class="hljs-params">vector</span><TreeNode*> s; <span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>> v; <span class="hljs-keyword">while</span> (root != <span class="hljs-params">NULL</span> || !s.empty()) { <span class="hljs-keyword">for</span> (; root != <span class="hljs-params">NULL</span>; root = root->left) s.push_back(root); v.push_back(s.back()->val); root = s.back()->right; s.pop_back(); } <span class="hljs-keyword">return</span> v; } }; ``` ``` Python Code: ``` <pre class="calibre18">``` <span class="hljs-title"># Definition for a binary tree node.</span> <span class="hljs-title"># class TreeNode:</span> <span class="hljs-title"># def __init__(self, x):</span> <span class="hljs-title"># self.val = x</span> <span class="hljs-title"># self.left = None</span> <span class="hljs-title"># self.right = None</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span>:</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">inorderTraversal</span><span class="hljs-params">(self, root: TreeNode)</span> -> List[int]:</span> <span class="hljs-string">""" 1. 递归法可以一行代码完成,无需讨论; 2. 迭代法一般需要通过一个栈保存节点顺序,我们这里直接使用列表 - 首先,我要按照中序遍历的顺序存入栈,这边用的逆序,方便从尾部开始处理 - 在存入栈时加入一个是否需要深化的参数 - 在回头取值时,这个参数应该是否,即直接取值 - 简单调整顺序,即可实现前序和后序遍历 """</span> <span class="hljs-title"># 递归法</span> <span class="hljs-title"># if root is None:</span> <span class="hljs-title"># return []</span> <span class="hljs-title"># return self.inorderTraversal(root.left)\</span> <span class="hljs-title"># + [root.val]\</span> <span class="hljs-title"># + self.inorderTraversal(root.right)</span> <span class="hljs-title"># 迭代法</span> result = [] stack = [(<span class="hljs-params">1</span>, root)] <span class="hljs-keyword">while</span> stack: go_deeper, node = stack.pop() <span class="hljs-keyword">if</span> node <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>: <span class="hljs-keyword">continue</span> <span class="hljs-keyword">if</span> go_deeper: <span class="hljs-title"># 左右节点还需继续深化,并且入栈是先右后左</span> stack.append((<span class="hljs-params">1</span>, node.right)) <span class="hljs-title"># 节点自身已遍历,回头可以直接取值</span> stack.append((<span class="hljs-params">0</span>, node)) stack.append((<span class="hljs-params">1</span>, node.left)) <span class="hljs-keyword">else</span>: result.append(node.val) <span class="hljs-keyword">return</span> result ``` ``` Java Code: - recursion ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>{ List<Integer> res = <span class="hljs-keyword">new</span> LinkedList<>(); <span class="hljs-function"><span class="hljs-keyword">public</span> List<Integer> <span class="hljs-title">inorderTraversal</span><span class="hljs-params">(TreeNode root)</span> </span>{ inorder(root); <span class="hljs-keyword">return</span> res; } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">inorder</span> <span class="hljs-params">(TreeNode root)</span> </span>{ <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) <span class="hljs-keyword">return</span>; inorder(root.left); res.add(root.val); inorder(root.right); } } ``` ``` - iteration ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Solution</span> </span>{ <span class="hljs-function"><span class="hljs-keyword">public</span> List<Integer> <span class="hljs-title">inorderTraversal</span><span class="hljs-params">(TreeNode root)</span> </span>{ List<Integer> res = <span class="hljs-keyword">new</span> ArrayList<> (); Stack<TreeNode> stack = <span class="hljs-keyword">new</span> Stack<> (); <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span> || !stack.isEmpty()) { <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span>) { stack.push(root); root = root.left; } root = stack.pop(); res.add(root.val); root = root.right; } <span class="hljs-keyword">return</span> res; } } ``` ``` ## 相关专题 - [二叉树的遍历](https://github.com/azl397985856/leetcode/blob/master/thinkings/binary-tree-traversal.md) 大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:<https://github.com/azl397985856/leetcode> 。 目前已经 37K star 啦。 大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 ![](https://img.kancloud.cn/cf/0f/cf0fc0dd21e94b443dd8bca6cc15b34b_900x500.jpg)