1、题目描述
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
解释:
示例 2:
输入:root = [1,2,3,4,5,null,8,null,null,6,7,9]
输出:[1,2,4,5,6,7,3,8,9]
解释:
示例 3:
输入:root = []
输出:[]
示例 4:
输入:root = [1]
输出:[1]
提示:
-
树中节点数目在范围
[0, 100]
内 -
-100 <= Node.val <= 100
进阶:递归算法很简单,你可以通过迭代算法完成吗?
2、方法1:迭代法
解题思路
迭代法通过显式地使用栈来模拟递归的隐式栈调用,避免了递归可能导致的栈溢出问题。
步骤:
-
初始化:创建一个空栈和一个空列表用于存储遍历结果。从根节点开始遍历。
-
访问节点并遍历左子树:
-
访问当前节点(将节点值加入结果列表)。
-
将当前节点压入栈中(以便后续回溯)。
-
转向当前节点的左子节点,重复上述过程。
-
-
回溯并遍历右子树:
-
当左子节点为空时,弹出栈顶节点(回溯到父节点)。
-
转向该节点的右子节点,重复上述过程。
-
-
终止条件:当栈为空且当前节点为空时,遍历结束。
时间复杂度:O(n),空间复杂度:O(n)(栈空间)
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode curNode = root;
while (curNode != null || !stack.isEmpty()) {
// 访问节点并遍历左子树
while (curNode != null) {
list.add(curNode.val); // 访问当前节点
stack.push(curNode); // 压栈以便回溯
curNode = curNode.left; // 转向左子节点
}
// 回溯并转向右子树
curNode = stack.pop(); // 弹出栈顶节点(父节点)
curNode = curNode.right; // 转向右子节点
}
return list;
}
3、方法2:递归
解题思路
递归法直接利用函数的调用栈来实现前序遍历,代码简洁但可能因递归深度过大导致栈溢出。
步骤:
-
递归终止条件:当前节点为空时,直接返回。
-
访问节点:将当前节点的值加入结果列表。
-
递归左子树:对当前节点的左子节点调用递归函数。
-
递归右子树:对当前节点的右子节点调用递归函数。
时间复杂度:O(n),空间复杂度:O(n)(调用栈)
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
preTree(root, list);
return list;
}
public void preTree(TreeNode node, List list) {
if (node == null) return;
list.add(node.val); // 访问当前节点
preTree(node.left, list); // 递归左子树
preTree(node.right, list); // 递归右子树
}