一、基本概念
二叉树遍历是指按照某种顺序访问树中所有节点,且每个节点只访问一次的过程。根据访问根节点的顺序不同,主要分为三种经典遍历方式:
二、深度优先遍历(DFS)
1. 前序遍历(Pre-order)
步骤:
-
访问根节点
-
递归遍历左子树
-
递归遍历右子树
递归实现:
void preOrder(TreeNode root) {
if (root == null) return;
System.out.print(root.val + " "); // 访问根
preOrder(root.left); // 左子树
preOrder(root.right); // 右子树
}
迭代实现(使用栈):
void preOrderIterative(TreeNode root) {
if (root == null) return;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
System.out.print(node.val + " ");
if (node.right != null) stack.push(node.right); // 右子节点先入栈
if (node.left != null) stack.push(node.left); // 左子节点后入栈
}
}
2. 中序遍历(In-order)
步骤:
-
递归遍历左子树
-
访问根节点
-
递归遍历右子树
递归实现:
void inOrder(TreeNode root) {
if (root == null) return;
inOrder(root.left); // 左子树
System.out.print(root.val + " "); // 访问根
inOrder(root.right); // 右子树
}
迭代实现:
void inOrderIterative(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
while (curr != null || !stack.isEmpty()) {
while (curr != null) { // 将左边界全部入栈
stack.push(curr);
curr = curr.left;
}
curr = stack.pop();
System.out.print(curr.val + " ");
curr = curr.right; // 转向右子树
}
}
3. 后序遍历(Post-order)
步骤:
-
递归遍历左子树
-
递归遍历右子树
-
访问根节点
递归实现:
void postOrder(TreeNode root) {
if (root == null) return;
postOrder(root.left); // 左子树
postOrder(root.right); // 右子树
System.out.print(root.val + " "); // 访问根
}
迭代实现(双栈法):
void postOrderIterative(TreeNode root) {
if (root == null) return;
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(root);
while (!stack1.isEmpty()) {
TreeNode node = stack1.pop();
stack2.push(node);
if (node.left != null) stack1.push(node.left);
if (node.right != null) stack1.push(node.right);
}
while (!stack2.isEmpty()) {
System.out.print(stack2.pop().val + " ");
}
}
三、广度优先遍历(BFS)/层序遍历
步骤:
-
从根节点开始,按层从上到下访问
-
每层从左到右访问节点
实现(使用队列):
void levelOrder(TreeNode root) {
if (root == null) return;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int levelSize = queue.size();
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll();
System.out.print(node.val + " ");
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
System.out.println(); // 换行显示不同层
}
}
四、遍历示例
给定二叉树:
1
/ \
2 3
/ \
4 5
遍历结果:
-
前序:1 → 2 → 4 → 5 → 3
-
中序:4 → 2 → 5 → 1 → 3
-
后序:4 → 5 → 2 → 3 → 1
-
层序:
1 2 3 4 5
五、特殊遍历方式
1. Morris遍历(空间复杂度O(1))
void morrisInOrder(TreeNode root) {
TreeNode curr = root;
while (curr != null) {
if (curr.left == null) {
System.out.print(curr.val + " ");
curr = curr.right;
} else {
TreeNode pre = curr.left;
while (pre.right != null && pre.right != curr) {
pre = pre.right;
}
if (pre.right == null) {
pre.right = curr; // 建立线索
curr = curr.left;
} else {
pre.right = null; // 删除线索
System.out.print(curr.val + " ");
curr = curr.right;
}
}
}
}
2. 之字形遍历
void zigzagLevelOrder(TreeNode root) {
if (root == null) return;
Deque<TreeNode> deque = new LinkedList<>();
boolean leftToRight = true;
deque.offer(root);
while (!deque.isEmpty()) {
int levelSize = deque.size();
for (int i = 0; i < levelSize; i++) {
if (leftToRight) {
TreeNode node = deque.pollFirst();
System.out.print(node.val + " ");
if (node.left != null) deque.offerLast(node.left);
if (node.right != null) deque.offerLast(node.right);
} else {
TreeNode node = deque.pollLast();
System.out.print(node.val + " ");
if (node.right != null) deque.offerFirst(node.right);
if (node.left != null) deque.offerFirst(node.left);
}
}
leftToRight = !leftToRight;
System.out.println();
}
}
理解这些遍历方式对于解决树相关问题至关重要,每种遍历方法在不同场景下都有其独特应用价值。
本文详细介绍了Android中样式和主题的使用方法,包括定义样式和主题的位置、样式和主题的XML写法、如何调用样式资源及主题资源,以及两者的区别。此外,还讲解了如何设置Android应用的横屏或竖屏。

1978

被折叠的 条评论
为什么被折叠?



