java中如何遍历栈_树的前中后顺遍历(递归、栈、颜色标记)---Java实现

二叉树的前中后顺遍历(递归、栈)Java实现

前序遍历

递归

import java.util.ArrayList;

import java.util.List;

public class PreOrder {

public List preOrder(TreeNode root) {

List res = new ArrayList<>();

helper(root, res);

return res;

}

public void helper(TreeNode root, List 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 stackTravers_preorder(TreeNode root) {

List res = new ArrayList<>();

Stack 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 inorderTraversal(TreeNode root) {

List res = new ArrayList<>();

helper(root, res);

return res;

}

// recursive

public void helper(TreeNode root, List 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 stackTraversl(TreeNode root) {

List res = new ArrayList<>();

Stack 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 postOrderTraversal(TreeNode root) {

List res = new ArrayList<>();

helper(root, res);

return res;

}

// recursive

public void helper(TreeNode root, List 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 stackTravers_postorder(TreeNode root) {

List res = new ArrayList<>();

Stack stack = new Stack<>();

Stack 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 inorderTraversal(TreeNode root) {

List res = new ArrayList<>();

if (root == null) {

return res;

}

Stack 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 preorder(Node root) {

List res = new ArrayList<>();

if (root == null) {

return res;

}

helper(root, res);

return res;

}

private void helper(Node curr, List res) {

if (curr != null) {

res.add(curr.val);

for (Node temp : curr.children) {

helper(temp, res);

}

}

}

}

class Node {

public int val;

public List children;

public Node() {}

public Node(int _val) {

val = _val;

}

public Node(int _val, List _children) {

val = _val;

children = _children;

}

}

栈-迭代

/**

* 使用栈,采用迭代的方式,来实现多叉树的遍历

*/

public class StackIterator {

public List preorder(Node root) {

// List stack = new LinkedList<>();

Stack stack = new Stack<>();

List 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 preorder(Node root) {

List res = new LinkedList<>();

if (root == null) {

return res;

}

Stack 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 children;

public Node() {}

public Node(int _val) {

val = _val;

}

public Node(int _val, List _children) {

val = _val;

children = _children;

}

}

// 定义含有颜色信息的树节点

class ColorNode{

Node node;

int color;

public ColorNode(Node node, int color) {

this.node = node;

this.color = color;

}

}

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值