# 0102. 二叉树的层序遍历 ## 题目地址(102. 二叉树的层序遍历) <https://leetcode-cn.com/problems/binary-tree-level-order-traversal/> ## 题目描述 ``` <pre class="calibre18">``` 给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。 示例: 二叉树:[3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回其层次遍历结果: [ [3], [9,20], [15,7] ] ``` ``` ## 前置知识 - 队列 ## 公司 - 阿里 - 腾讯 - 百度 - 字节 ## 思路 这是一个典型的二叉树遍历问题, 关于二叉树遍历,我总结了一个[专题](https://github.com/azl397985856/leetcode/blob/master/thinkings/binary-tree-traversal.md),大家可以先去看下那个,然后再来刷这道题。 这道题可以借助`队列`实现,首先把root入队,然后入队一个特殊元素Null(来表示每层的结束)。 然后就是while(queue.length), 每次处理一个节点,都将其子节点(在这里是left和right)放到队列中。 然后不断的出队, 如果出队的是null,则表式这一层已经结束了,我们就继续push一个null。 如果不入队特殊元素Null来表示每层的结束,则在while循环开始时保存当前队列的长度,以保证每次只遍历一层(参考下面的C++ Code)。 > 如果采用递归方式,则需要将当前节点,当前所在的level以及结果数组传递给递归函数。在递归函数中,取出节点的值,添加到level参数对应结果数组元素中(参考下面的C++ Code 或 Python Code)。 ## 关键点解析 - 队列 - 队列中用Null(一个特殊元素)来划分每层 - 树的基本操作- 遍历 - 层次遍历(BFS) - 注意塞入null的时候,判断一下当前队列是否为空,不然会无限循环 ## 代码 - 语言支持:JS,C++,Python3 Javascript Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * @param {TreeNode} root * @return {number[][]} */</span> <span class="hljs-keyword">var</span> levelOrder = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">root</span>) </span>{ <span class="hljs-keyword">if</span> (!root) <span class="hljs-keyword">return</span> []; <span class="hljs-keyword">const</span> items = []; <span class="hljs-title">// 存放所有节点</span> <span class="hljs-keyword">const</span> queue = [root, <span class="hljs-params">null</span>]; <span class="hljs-title">// null 简化操作</span> <span class="hljs-keyword">let</span> levelNodes = []; <span class="hljs-title">// 存放每一层的节点</span> <span class="hljs-keyword">while</span> (queue.length > <span class="hljs-params">0</span>) { <span class="hljs-keyword">const</span> t = queue.shift(); <span class="hljs-keyword">if</span> (t) { levelNodes.push(t.val) <span class="hljs-keyword">if</span> (t.left) { queue.push(t.left); } <span class="hljs-keyword">if</span> (t.right) { queue.push(t.right); } } <span class="hljs-keyword">else</span> { <span class="hljs-title">// 一层已经遍历完了</span> items.push(levelNodes); levelNodes = []; <span class="hljs-keyword">if</span> (queue.length > <span class="hljs-params">0</span>) { queue.push(<span class="hljs-params">null</span>) } } } <span class="hljs-keyword">return</span> items; }; ``` ``` 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-title">// 迭代</span> <span class="hljs-keyword">class</span> Solution { <span class="hljs-keyword">public</span>: <span class="hljs-params">vector</span><<span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>>> levelOrder(TreeNode* root) { <span class="hljs-keyword">auto</span> ret = <span class="hljs-params">vector</span><<span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>>>(); <span class="hljs-keyword">if</span> (root == <span class="hljs-params">nullptr</span>) <span class="hljs-keyword">return</span> ret; <span class="hljs-keyword">auto</span> q = <span class="hljs-params">vector</span><TreeNode*>(); q.push_back(root); <span class="hljs-keyword">auto</span> level = <span class="hljs-params">0</span>; <span class="hljs-keyword">while</span> (!q.empty()) { <span class="hljs-keyword">auto</span> sz = q.size(); ret.push_back(<span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>>()); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span> i = <span class="hljs-params">0</span>; i < sz; ++i) { <span class="hljs-keyword">auto</span> t = q.front(); q.erase(q.begin()); ret[level].push_back(t->val); <span class="hljs-keyword">if</span> (t->left != <span class="hljs-params">nullptr</span>) q.push_back(t->left); <span class="hljs-keyword">if</span> (t->right != <span class="hljs-params">nullptr</span>) q.push_back(t->right); } ++level; } <span class="hljs-keyword">return</span> ret; } }; <span class="hljs-title">// 递归</span> <span class="hljs-keyword">class</span> Solution { <span class="hljs-keyword">public</span>: <span class="hljs-params">vector</span><<span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>>> levelOrder(TreeNode* root) { <span class="hljs-params">vector</span><<span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>>> v; levelOrder(root, <span class="hljs-params">0</span>, v); <span class="hljs-keyword">return</span> v; } <span class="hljs-keyword">private</span>: <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">levelOrder</span><span class="hljs-params">(TreeNode* root, <span class="hljs-keyword">int</span> level, <span class="hljs-params">vector</span><<span class="hljs-params">vector</span><<span class="hljs-keyword">int</span>>>& v)</span> </span>{ <span class="hljs-keyword">if</span> (root == <span class="hljs-params">NULL</span>) <span class="hljs-keyword">return</span>; <span class="hljs-keyword">if</span> (v.size() < level + <span class="hljs-params">1</span>) v.resize(level + <span class="hljs-params">1</span>); v[level].push_back(root->val); levelOrder(root->left, level + <span class="hljs-params">1</span>, v); levelOrder(root->right, level + <span class="hljs-params">1</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">levelOrder</span><span class="hljs-params">(self, root: TreeNode)</span> -> List[List[int]]:</span> <span class="hljs-string">"""递归法"""</span> <span class="hljs-keyword">if</span> root <span class="hljs-keyword">is</span> <span class="hljs-keyword">None</span>: <span class="hljs-keyword">return</span> [] result = [] <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_to_result</span><span class="hljs-params">(level, node)</span>:</span> <span class="hljs-string">"""递归函数 :param level int 当前在二叉树的层次 :param node TreeNode 当前节点 """</span> <span class="hljs-keyword">if</span> level > len(result) - <span class="hljs-params">1</span>: result.append([]) result[level].append(node.val) <span class="hljs-keyword">if</span> node.left: add_to_result(level+<span class="hljs-params">1</span>, node.left) <span class="hljs-keyword">if</span> node.right: add_to_result(level+<span class="hljs-params">1</span>, node.right) add_to_result(<span class="hljs-params">0</span>, root) <span class="hljs-keyword">return</span> result ``` ``` ***复杂度分析*** - 时间复杂度:O(N)O(N)O(N),其中N为树中节点总数。 - 空间复杂度:O(N)O(N)O(N),其中N为树中节点总数。 更多题解可以访问我的LeetCode题解仓库:<https://github.com/azl397985856/leetcode> 。 目前已经30K star啦。 关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。 ## 扩展 实际上这道题方法很多, 比如经典的三色标记法。 ## 相关题目 - [103.binary-tree-zigzag-level-order-traversal](103.binary-tree-zigzag-level-order-traversal.html) - [104.maximum-depth-of-binary-tree](104.maximum-depth-of-binary-tree.html) ## 相关专题 - [二叉树的遍历](https://github.com/azl397985856/leetcode/blob/master/thinkings/binary-tree-traversal.md)