二叉树遍历方法解释:
- 前序遍历(Pre-order Traversal)
访问顺序:根节点 -> 左子树 -> 右子树 - 中序遍历(In-order Traversal)
访问顺序:左子树 -> 根节点 -> 右子树 - 后序遍历(Post-order Traversal)
访问顺序:左子树 -> 右子树 -> 根节点
代码实现
1.递归
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
preorderHelper(root, result);
return result;
}
private void preorderHelper(TreeNode node, List<Integer> result) {
if (node == null) {
return;
}
result.add(node.val); // 访问根节点
preorderHelper(node.left, result); // 遍历左子树
preorderHelper(node.right, result); // 遍历右子树
}
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
inorderHelper(root, result);
return result;
}
private void inorderHelper(TreeNode node, List<Integer> result) {
if (node == null) {
return;
}
inorderHelper(node.left, result); // 遍历左子树
result.add(node.val); // 访问根节点
inorderHelper(node.right, result); // 遍历右子树
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
postorderHelper(root, result);
return result;
}
private void postorderHelper(TreeNode node, List<Integer> result) {
if (node == null) {
return;
}
postorderHelper(node.left, result); // 遍历左子树
postorderHelper(node.right, result); // 遍历右子树
result.add(node.val); // 访问根节点
}
}
2.使用数据结构-栈
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
class Solution {
public List<Integer> preorderTraversal(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;
}
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left; // 遍历左子树
}
cur = stack.pop();
result.add(cur.val); // 访问根节点
cur = cur.right; // 遍历右子树
}
return result;
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null) {
return result;
}
Stack<TreeNode> stack = new Stack<>();
Stack<TreeNode> output = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
output.push(node); // 将节点压入输出栈
if (node.left != null) {
stack.push(node.left); // 左子节点先入栈
}
if (node.right != null) {
stack.push(node.right); // 右子节点后入栈
}
}
while (!output.isEmpty()) {
result.add(output.pop().val); // 从输出栈弹出节点并访问
}
return result;
}
}
3.使用Morris遍历算法
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public class MorrisTraversal {
public void inorderTraversal(TreeNode root) {
TreeNode current = root;
while (current != null) {
if (current.left == null) {
// 访问当前节点
System.out.print(current.val + " ");
current = current.right;
} else {
// 找到当前节点左子树的最右节点
TreeNode pre = current.left;
while (pre.right != null && pre.right != current) {
pre = pre.right;
}
if (pre.right == null) {
// 建立线索
pre.right = current;
current = current.left;
} else {
// 恢复树结构
pre.right = null;
// 访问当前节点
System.out.print(current.val + " ");
current = current.right;
}
}
}
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.right = new TreeNode(2);
root.right.left = new TreeNode(3);
MorrisTraversal morris = new MorrisTraversal();
morris.inorderTraversal(root); // 输出: 1 3 2
}
}
总结
递归:简单直观,适用于所有遍历方式,但使用额外的递归栈空间。
栈:使用显式栈来模拟递归过程,适用于所有遍历方式。
Morris遍历:不使用额外空间,适用于中序遍历,但会修改树的结构并在遍历结束后恢复。
选择哪种方法取决于具体的需求和约束条件。