从一道算法题理解递归

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hqqqqqqq555/article/details/84346557

从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方法中,此时栈结构:在这里插入图片描述
顺序往下执行:

扫描二维码关注公众号,回复: 5413323 查看本文章
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节点的遍历。

总结:
递归算法在内存中就是开辟新的栈空间,用不同的参数(本例是各个节点),执行同样的方法;遇到递归出口,会返回结果到上层栈,并且销毁当前栈空间,直到各层栈空间都执行完,返回最终结果。

以上就是粗浅的理解。

猜你喜欢

转载自blog.csdn.net/hqqqqqqq555/article/details/84346557