从leetcode上的算法题 589.N叉树的前序遍历来了解递归的过程。
题目背景:
给定一个 N 叉树,返回其节点值的前序遍历。
例如,给定一个 3叉树 :
返回其前序遍历: [1,3,5,6,2,4]。
节点定义:
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val,List<Node> _children) {
val = _val;
children = _children;
}
};
算法:
class Solution {
public List<Integer> preorder(Node root) {
List<Integer> list = new ArrayList<>();
if(root == null){return list;}
//先序遍历,先访问根节点
list.add(root.val);
//对每个子节点,进行递归访问
for(int i = 0;i < root.children.size();i++){
list.addAll(preorder(root.children.get(i)));
}
return list;
}
}
过程模拟:
为描述方便,给每个节点起名:root,c1-c5。
下图描述此树在内存中的存储:
其中,蓝色表示内存地址,黄色是Node对象,绿色是List对象(假定是顺序存储)。
进入preorder(Node root)方法,参数就是root(传进来的是地址)。栈结构如下图:
List<Integer> list = new ArrayList<>();
if(root == null){return list;}
list.add(root.val);
1.实例化一个顺序表(假设地址为6000)。
2.明显root不为空。
3.list添加了root的值1。
此时堆栈情况:
for(int i = 0;i < root.children.size();i++){
list.addAll(preorder(root.children.get(i)));
}
此处对root的子节点进行遍历。
首先会遍历到c1,把c1作为参数传入到preorder方法中,此时栈结构:
顺序往下执行:
List<Integer> list = new ArrayList<>();
if(root == null){return list;}
list.add(root.val);
1.实例化一个顺序表(假设地址为6001)。
2.明显root(c1)不为空。
3.list添加了root的值3。
继续往下走
for(int i = 0;i < root.children.size();i++){
list.addAll(preorder(root.children.get(i)));
}
会对c1的子节点进行遍历,首先访问到c4。把c4作为参数传入preorder方法。
List<Integer> list = new ArrayList<>();
if(root == null){return list;}
list.add(root.val);
执行后
然后遍历c4子节点(为null),返回一个空的list。这里return会出栈,红色部分会销毁,返回一个list地址(6003)到上一级的list.addAll()作为参数,由于为空,6002的list没有改变。
然后c4会执行到return list(6002),出栈,销毁c4栈空间,把list6002返回到c1的list.addAll()方法作为参数。
此时的栈:
接下来c1里的for循环继续进行,访问到c5。
与c4类似,过程就不详述了。c5会return回来一个只有一个值(6)的list,这样6001的list会变成:
到此,c1的子节点遍历结束,返回6001的list到上层的list.addAll()方法作为参数。执行后list会变成:
此时的堆栈结构:
接下来开始对c2的访问,由于c2是叶子节点,会返回只有一个值(2)的list,执行list.addAll()后list6000会变为:
同理,访问完c3后,list6000会变为:
至此,完成了对root节点的遍历。
总结:
递归算法在内存中就是开辟新的栈空间,用不同的参数(本例是各个节点),执行同样的方法;遇到递归出口,会返回结果到上层栈,并且销毁当前栈空间,直到各层栈空间都执行完,返回最终结果。
以上就是粗浅的理解。