音乐
暂未播放
LeetCode | 二叉树的中序遍历
分类:二叉树 / 深度优先搜索 / 栈
题目#
给定一棵二叉树的根节点 root,返回它的中序遍历结果。
中序遍历的顺序是:左子树、当前节点、右子树。
示例:
1 42 / \3 2 64 / / \5 1 5 76输入:root = [4,2,6,1,null,5,7]7输出:[1,2,4,5,6,7]其余例子略
讲解#
基础概念#
树是一种像倒过来的树一样的数据结构:从一个起点往下分叉。
节点就是树里的一个元素。每个节点通常会保存一个值,比如图里的 1、2、3。
根节点就是整棵树最上面的节点,也就是题目里的 root。如果 root = [],说明这棵树是空的。
二叉树表示每个节点最多有两个孩子:左孩子和右孩子。以某个节点的左孩子为起点继续往下看,就是它的左子树;以右孩子为起点继续往下看,就是它的右子树。
深度优先搜索就是先沿着一条路尽量往深处走,走不下去了再退回来换另一条路。二叉树的前序、中序、后序遍历都属于这种思路。
中序遍历专门指二叉树里的“左、根、右”:先访问左子树,再访问当前节点,最后访问右子树。
栈是LIFO。stack.append(x) 表示把 x 放进栈,stack.pop() 表示取出最后放进去的元素。
这道题的核心就是记住中序遍历的访问顺序:左、根、右。
递归法#
递归法最直观,但要先注意一点:代码里的 root 不一定永远是整棵树最上面的根节点,它更像是“当前正在处理的节点”。
如果左边或右边没有节点,对应的 root.left 或 root.right 就是 None。
递归函数 inorder(root) 做的事情是:
- 如果当前节点是空的,直接返回。
- 先递归处理当前节点的左子树。
- 左边处理完以后,把当前节点的值加入结果。
- 最后递归处理当前节点的右子树。
以 root = [4,2,6,1,null,5,7] 为例:
执行过程可以简单看成:
1inorder(4)2 inorder(4.left) -> inorder(2)3 inorder(2.left) -> inorder(1)4 inorder(1.left) -> 空,返回5 加入 16 inorder(1.right) -> 空,返回7 加入 28 inorder(2.right) -> 空,返回9 加入 410 inorder(4.right) -> inorder(6)11 inorder(6.left) -> inorder(5)12 inorder(5.left) -> 空,返回13 加入 514 inorder(5.right) -> 空,返回15 加入 616 inorder(6.right) -> inorder(7)17 inorder(7.left) -> 空,返回18 加入 719 inorder(7.right) -> 空,返回所以结果是 [1, 2, 4, 5, 6, 7]。
迭代栈法#
递归本质上也在用系统调用栈。迭代法就是自己准备一个 stack 来模拟递归。
中序遍历是“左、根、右”,所以一个节点不能一看到就立刻加入结果,必须先把它左边的节点处理完。
栈里保存的就是这些“还不能访问,先等一下”的节点。
具体过程是:
- 当前节点不为空时,一直往左走,路过的节点都放进栈。
- 走到空节点,说明左边已经到底了。
- 从栈里
pop一个节点,这个节点的左边已经处理完,现在可以加入结果。 - 然后转向这个节点的右子树,继续重复。
以 root = [4,2,6,1,null,5,7] 为例:
1 42 / \3 2 64 / / \5 1 5 7执行过程可以简单看成:
1while root or stack:2 while root:3 stack.append(root)4 root = root.left5放入 4,往左到 26放入 2,往左到 17放入 1,往左到空8
9root = stack.pop()10res.append(root.val)11root = root.right12pop 1,加入 1,1 没有右边(跳出while root,继续执行上面)13pop 2,加入 2,2 没有右边14
15pop 4,加入 4,转向 4 的右边 616
17放入 6,往左到 518放入 5,往左到空19pop 5,加入 5,5 没有右边20
21pop 6,加入 6,转向 6 的右边 722放入 7,往左到空23pop 7,加入 7,7 没有右边所以结果是 [1, 2, 4, 5, 6, 7]。
复杂度#
- 递归法:时间复杂度
O(n),空间复杂度O(n) - 迭代栈法:时间复杂度
O(n),空间复杂度O(n)
代码#
递归法#
源码#
1class Solution:2 def inorderTraversal(self, root: "TreeNode") -> list[int]:3 res = []4
5 def inorder(root):6 if not root:7 return8 inorder(root.left)9 res.append(root.val)10 inorder(root.right)11
12 inorder(root)13 return res迭代栈法#
源码#
1class Solution:2 def inorderTraversal(self, root: "TreeNode") -> list[int]:3 res = []4 stack = []5
6 while root or stack:7 while root:8 stack.append(root)9 root = root.left10
11 root = stack.pop()12 res.append(root.val)13 root = root.right14
15 return res测试#
1class TreeNode:2 def __init__(self, val=0, left=None, right=None):3 self.val = val4 self.left = left5 self.right = right6
7
8sol = Solution()9
10root = TreeNode(1)11root.right = TreeNode(2)12root.right.left = TreeNode(3)13assert sol.inorderTraversal(root) == [1, 3, 2]14
15root = TreeNode(4)16root.left = TreeNode(2)17root.right = TreeNode(6)18root.left.left = TreeNode(1)19root.right.left = TreeNode(5)20root.right.right = TreeNode(7)21assert sol.inorderTraversal(root) == [1, 2, 4, 5, 6, 7]22
23root = TreeNode(1)24root.left = TreeNode(2)25root.right = TreeNode(3)26root.left.left = TreeNode(4)27root.left.right = TreeNode(5)28root.left.right.left = TreeNode(6)29root.left.right.right = TreeNode(7)30root.right.right = TreeNode(8)31root.right.right.left = TreeNode(9)32assert sol.inorderTraversal(root) == [4, 2, 6, 5, 7, 1, 3, 9, 8]33
34assert sol.inorderTraversal(None) == []35assert sol.inorderTraversal(TreeNode(1)) == [1]36
37print("PASS")参考资料#
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
部分内容可能已过时
评论区
分享你的想法,与大家交流讨论
音乐
暂未播放



