树的前中后顺遍历(递归、栈、颜色标记)---Java实现
二叉树的前中后顺遍历(递归、栈)Java实现
前序遍历
- 递归
import java.util.ArrayList;
import java.util.List;
public class PreOrder {
public List<Integer> preOrder(TreeNode root) {
List<Integer> res = new ArrayList<>();
helper(root, res);
return res;
}
public void helper(TreeNode root, List<Integer> res) {
if (root != null) {
res.add(root.val);
if (root.left != null) {
helper(root.left, res);
}
if (root.right != null) {
helper(root.right, res);
}
}
}
}
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x;}
}
- 栈
public List<Integer> stackTravers_preorder(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
while (curr != null || !stack.isEmpty()) {
while (curr != null) {
res.add(curr.val);
stack.push(curr);
curr = curr.left;
}
if (!stack.isEmpty()) {
curr = stack.pop();
curr = curr.right;
}
}
return res;
}
中序遍历
- 递归
import java.util.ArrayList;
import java.util.List;
public class PreOrder {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
helper(root, res);
return res;
}
// recursive
public void helper(TreeNode root, List<Integer> res) {
if (root != null) {
if (root.left != null) {
helper(root.left, res);
}
res.add(root.val);
if (root.right != null) {
helper(root.right, res);
}
}
}
}
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x;}
}
- 栈
public List<Integer> stackTraversl(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
while (curr != null || !stack.isEmpty()) {
// push the left tree into stack
while (curr != null) {
stack.push(curr);
curr = curr.left;
}
// when reached leaf node
curr = stack.pop();
res.add(curr.val);
curr = curr.right;
}
return res;
}
后续遍历
- 递归
import java.util.ArrayList;
import java.util.List;
public class PostOrder {
public List<Integer> postOrderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
helper(root, res);
return res;
}
// recursive
public void helper(TreeNode root, List<Integer> res) {
if (root != null) {
if (root.left != null) {
helper(root.left, res);
}
if (root.right != null) {
helper(root.right, res);
}
res.add(root.val);
}
}
}
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x;}
}
- 栈
算法核心思想:
首先要搞清楚先序、中序、后序的非递归算法共同之处:用栈来保存先前走过的路径,以便可以在访问完子树后,可以利用栈中的信息,回退到当前节点的双亲节点,进行下一步操作。
后序遍历的非递归算法是三种顺序中最复杂的,原因在于,后序遍历是先访问左、右子树,再访问根节点,而在非递归算法中,利用栈回退到时,并不知道是从左子树回退到根节点,还是从右子树回退到根节点,如果从左子树回退到根节点,此时就应该去访问右子树,而如果从右子树回退到根节点,此时就应该访问根节点。所以相比前序和后序,必须得在压栈时添加信息,以便在退栈时可以知道是从左子树返回,还是从右子树返回进而决定下一步的操作。
————————————————
版权声明:本文为CSDN博主「coder__666」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/coder__666/article/details/80349039
public List<Integer> stackTravers_postorder(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
Stack<Integer> stack2 = new Stack<>(); // 辅助栈,用于保存,压入栈的是左子树还是右子树
TreeNode curr = root;
int left = 1; // note left tree
int right = 2; // note right tree
while (curr != null || !stack.isEmpty()) {
while (curr != null) {
stack.push(curr);
stack2.push(left);
curr = curr.left;
}
while (!stack.isEmpty() && stack2.peek() == right) {
// 如果是从左子节点返回父节点,则任务完成,将两个栈的栈顶弹出,记录结果
stack2.pop();
res.add(stack.pop().val);
}
if (!stack.isEmpty() && stack2.peek() == left) {
// 如果是从左子树返回,则先将辅助栈弹出栈顶,下一个应该压栈的是右子树
//
stack2.pop();
stack2.push(right);
curr = stack.peek().right;
}
}
return res;
}
颜色标记法(通用)
方题解中介绍了三种方法来完成树的中序遍历,包括:
递归
借助栈的迭代方法
莫里斯遍历
在树的深度优先遍历中(包括前序、中序、后序遍历),递归方法最为直观易懂,但考虑到效率,我们通常不推荐使用递归。
栈迭代方法虽然提高了效率,但其嵌套循环却非常烧脑,不易理解,容易造成“一看就懂,一写就废”的窘况。而且对于不同的遍历顺序(前序、中序、后序),循环结构差异很大,更增加了记忆负担。
因此,我在这里介绍一种“颜色标记法”(瞎起的名字……),兼具栈迭代方法的高效,又像递归方法一样简洁易懂,更重要的是,这种方法对于前序、中序、后序遍历,能够写出完全一致的代码。
其核心思想如下:
使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
如果遇到的节点为灰色,则将节点的值输出。
public class ColorMethod {
// 定义含有颜色信息的树节点
class ColorNode{
TreeNode node;
int color;
public ColorNode(TreeNode node, int color) {
this.node = node;
this.color = color;
}
}
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x;}
}
private final int white = 0;
private final int gray = 1;
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Stack<ColorNode> stack = new Stack<>();
stack.push(new ColorNode(root, white));
while (!stack.isEmpty()) {
ColorNode curr = stack.pop();
// 如果此节点没有访问过
if (curr.color == white) {
if (curr.node.right != null) {
stack.push(new ColorNode(curr.node.right, white));
}
// 置为灰色
stack.push(new ColorNode(curr.node, gray));
if (curr.node.left != null) {
stack.push(new ColorNode(curr.node.left, white));
}
} else {
res.add(curr.node.val);
}
}
return res;
}
}
N叉树的前序遍历
递归
/**
* N叉树的前序遍历
*/
public class Recursive {
// 使用递归来前序遍历
public List<Integer> preorder(Node root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
helper(root, res);
return res;
}
private void helper(Node curr, List<Integer> res) {
if (curr != null) {
res.add(curr.val);
for (Node temp : curr.children) {
helper(temp, res);
}
}
}
}
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
}
栈-迭代
/**
* 使用栈,采用迭代的方式,来实现多叉树的遍历
*/
public class StackIterator {
public List<Integer> preorder(Node root) {
// List<Node> stack = new LinkedList<>();
Stack<Node> stack = new Stack<>();
List<Integer> res = new LinkedList<>();
if (root == null) {
return res;
}
stack.add(root);
while (!stack.isEmpty()) {
// 前序遍历,因此是root left tight
// 入栈的顺序要反过来
Node curr = stack.pop();
res.add(curr.val);
if (curr.children != null) {
Collections.reverse(curr.children);
for (Node temp : curr.children) {
stack.push(temp);
}
}
}
return res;
}
颜色标记法
public class ColorMethod {
private final int white = 0;
private final int gray = 1;
public List<Integer> preorder(Node root) {
List<Integer> res = new LinkedList<>();
if (root == null) {
return res;
}
Stack<ColorNode> stack = new Stack<>();
stack.push(new ColorNode(root, white));
while (!stack.isEmpty()) {
ColorNode curr = stack.pop();
if (curr.color == white) {
// 以相反的顺序压栈
if (curr.node.children != null) {
Collections.reverse(curr.node.children);
for (Node temp : curr.node.children) {
stack.push(new ColorNode(temp, white));
}
stack.push(new ColorNode(curr.node, gray));
}
} else {
res.add(curr.node.val);
}
}
return res;
}
}
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
}
// 定义含有颜色信息的树节点
class ColorNode{
Node node;
int color;
public ColorNode(Node node, int color) {
this.node = node;
this.color = color;
}
}