遍历多叉树

随便画一个树,写代码遍历它

OK,树的结构这么描述

public class TreeNode {
        private String name;
        private TreeNode parent;
        private List<TreeNode> children = new ArrayList<>();
        //setter,getter
}

递归

public static void Recursion(TreeNode root) {
    System.out.print(root.getName());
    for (TreeNode treeNode : root.getChildren()) {
        Recursion(treeNode);
    }
}
//结果为:ABEHIJFCDG

但如果这个树的非常复杂,非常深,该怎么办?

递归这种方式有什么缺点?

先从jvm的栈讲起,先来一张栈帧的结构图

每当启动一个新线程的时候,java虚拟机都会为它分配一个java栈。java以栈帧为单位保存线程的运行状态。虚拟机只会对java栈执行两种操作:以栈帧为单位的压栈或者出栈。

通俗点说,每个方法就是一个栈帧,方法要执行就得压栈,return或者抛异常了就出栈.

递归就会在当前线程的栈中不断的入栈,入的多了就爆了,就会抛出java.lang.StackOverflowError

另外,对于一个方法,内存调用是这样的


刚才在栈帧中的局部变量,如果是对象就会是一个引用,ref只有4byte,但对象本身会在堆(heap)中创建,递归执行完了,出栈了,栈不用管了,但堆里面的对象就得等GC了.

这么一说,递归还真不好用呢,所以非递归方式怎么写呢?
遍历有两种方式,广度优先和深度优先

广度优先

/**
 * 广度优先需要构建一个先进先出的队列
 *
 * @param root
 */
public static void breadthFirst(TreeNode root) {
    Deque<TreeNode> nodeDeque = new LinkedList<>();
    TreeNode node = root;
    nodeDeque.push(node);
    while (!nodeDeque.isEmpty()) {
        node = nodeDeque.pop();
        System.out.print(node.getName());
        for (TreeNode treeNode : node.getChildren()) {
            nodeDeque.addLast(treeNode);
        }
    }
}
//结果为ABCDEFGHIJ

深度优先

/**
 * 深度优先需要构建一个后进先出的栈,
 * 不使用Stack是因为java的Stack功能略多
 *
 * @param root
 */
public static void depthFirst(TreeNode root) {
    Deque<TreeNode> nodeDeque = new LinkedList<>();
    TreeNode node = root;
    nodeDeque.push(node);
    while (!nodeDeque.isEmpty()) {
        node = nodeDeque.pop();
        System.out.print(node.getName());
        for (TreeNode treeNode : node.getChildren()) {
            nodeDeque.push(treeNode);
        }
    }
}
//结果为ADGCBFEJIH