吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 616|回复: 2
收起左侧

[学习记录] 如何调试递归程序,有何技巧?

[复制链接]
黑白客 发表于 2023-3-27 18:41

前言

正所谓工欲善其事必先利其器
之前的递归调试,我都是全靠脑洞和头发。

先说明我使用的是idea调试java编写的leetcode的[200]岛屿数量  Medium  2023-03-08  191的时候被单步调试弄得快要疯了才来搜索这个问题的,然后看到回答里面说打印,我真的想捶我自己(别笑QAQ,我只是一时没想到)。


1 效果展示

直接看效果:

调用了第1层low函数 | 参数 l r 0 0
0 1 1 1 0 
1 1 0 1 0 
1 1 0 0 0 
0 0 0 0 0 

    调用了第2层low函数 | 参数 l r 0 1
    0 0 1 1 0 
    1 1 0 1 0 
    1 1 0 0 0 
    0 0 0 0 0 

        调用了第3层low函数 | 参数 l r 0 2
        0 0 0 1 0 
        1 1 0 1 0 
        1 1 0 0 0 
        0 0 0 0 0 

            调用了第4层low函数 | 参数 l r 0 3
            0 0 0 0 0 
            1 1 0 1 0 
            1 1 0 0 0 
            0 0 0 0 0 

                调用了第5层low函数 | 参数 l r 1 3
                0 0 0 0 0 
                1 1 0 0 0 
                1 1 0 0 0 
                0 0 0 0 0 

                退出了第5层low函数 | 参数 l r 1 3
                0 0 0 0 0 
                1 1 0 0 0 
                1 1 0 0 0 
                0 0 0 0 0 

            退出了第4层low函数 | 参数 l r 0 3
            0 0 0 0 0 
            1 1 0 0 0 
            1 1 0 0 0 
            0 0 0 0 0 

        退出了第3层low函数 | 参数 l r 0 2
        0 0 0 0 0 
        1 1 0 0 0 
        1 1 0 0 0 
        0 0 0 0 0 

        调用了第3层low函数 | 参数 l r 1 1
        0 0 0 0 0 
        1 0 0 0 0 
        1 1 0 0 0 
        0 0 0 0 0 

            调用了第4层low函数 | 参数 l r 1 0
            0 0 0 0 0 
            0 0 0 0 0 
            1 1 0 0 0 
            0 0 0 0 0 

                调用了第5层low函数 | 参数 l r 2 0
                0 0 0 0 0 
                0 0 0 0 0 
                0 1 0 0 0 
                0 0 0 0 0 

                    调用了第6层low函数 | 参数 l r 2 1
                    0 0 0 0 0 
                    0 0 0 0 0 
                    0 0 0 0 0 
                    0 0 0 0 0 

                    退出了第6层low函数 | 参数 l r 2 1
                    0 0 0 0 0 
                    0 0 0 0 0 
                    0 0 0 0 0 
                    0 0 0 0 0 

                退出了第5层low函数 | 参数 l r 2 0
                0 0 0 0 0 
                0 0 0 0 0 
                0 0 0 0 0 
                0 0 0 0 0 

            退出了第4层low函数 | 参数 l r 1 0
            0 0 0 0 0 
            0 0 0 0 0 
            0 0 0 0 0 
            0 0 0 0 0 

        退出了第3层low函数 | 参数 l r 1 1
        0 0 0 0 0 
        0 0 0 0 0 
        0 0 0 0 0 
        0 0 0 0 0 

    退出了第2层low函数 | 参数 l r 0 1
    0 0 0 0 0 
    0 0 0 0 0 
    0 0 0 0 0 
    0 0 0 0 0 

退出了第1层low函数 | 参数 l r 0 0
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 

1

2 递归代码

下面是我要调试的递归的代码:


    //输入:grid = [
//  ["1","1","1","1","0"],
//  ["1","1","0","1","0"],
//  ["1","1","0","0","0"],
//  ["0","0","0","0","0"]
//]

    public void low(int l , int r,Character[][] grid){

        grid[l][r] = '0' ;

        int length = grid[l].length;
        int len = grid.length;
        /*右*/
        while( r+1 < length && grid[l][r+1] == '1' ){

            low(l , ++r,grid);
        }

        /*左*/
        while(0< r-1 && grid[l][r-1] == '1' ){
            low(l , r--,grid);
//          grid[l][r-1] = '0';
//          r--;
        }

        /*上*/
        while(0<l-1 && grid[l-1][r] == '1' ){
            low(l-- , r,grid);
//          grid[l-1][r] = '0';
//          l--;
        }

        /*下*/
        while(l+1 < len && grid[l+1][r] == '1' ){
            low(++l , r,grid);
//          grid[l+1][r] = '0';
//          l++;
        }
    }

}

3 函数头下面输出

首先我在函数头下面输出调用信息:

    System.out.println("调用了low函数 | 参数 l r grid"+l+r+grid);

我还想知道每一个调用函数是第几层,如果这一大坨输出有缩进会不会更好一点呢?缩进简单,输出制表符“\t”就好。但是输出几个呢?

所以需要用一个计数的变量来计算目前递归的层数,进而产生缩进效果。有两个方法,一个方法是我敲这些字的时候想到的,全局变量,在函数头自增1,在函数尾自减1,就可以知道当前递归层数。

我用的是静态变量。对于一个函数里面的静态变量来说,使用static关键字声明并初始化它之后,这条声明语句会在下一次执行时忽略,并且这个静态变量会一直活到程序结束,不像其他函数中声明的局部变量一样命短。其实这也相当于是一种全局变量,只不过是在调用这个函数的时候才创建出来。其它和第一种方法一样,在函数头自增1,在函数尾自减1。

然后在想要缩进的地方前面加上:

static  Integer leve = 0;
        String lev = "";
        for (Integer i = 0; i < leve; i++) {
            lev += "\t";
        }
        System.out.println(lev+"调用了第"+ leve++ +"层low函数 | 参数 l r "+l+" "+r);
        for (int i = 0; i < len; i++) {
            int length1 = grid[i].length;
            System.out.print(lev);
            for (int i1 = 0; i1 < length1; i1++) {
                System.out.print(  grid[i][i1]+" ");
            }
            System.out.println();
        }
        System.out.println();

// 程序代码

        System.out.println(lev+"退出了第"+ leve-- +"层low函数 | 参数 l r "+l+" "+r);
        for (int i = 0; i < len; i++) {
            int length1 = grid[i].length;
            System.out.print(lev);
            for (int i1 = 0; i1 < length1; i1++) {
                System.out.print(  grid[i][i1]+" ");
            }
            System.out.println();
        }
        System.out.println();

4 调试步骤

分析打印的日志
然后在这里面找到有问题的函数调用,设置参数值的条件断点:

点击打上断点之后,右击断点,输入条件即可。

5 完整源码

因为博主在看别的博客的时候,有时看到截取的片段代码很难使用,或者理解。
这里提供操作所用的完整代码仅供参考,有帮助记得点赞收藏哦!

public class P200_NumberOfIslands{
    static  Integer leve = 0;
     public static void main(String[] args) {
         //测试代码
         Solution solution = new P200_NumberOfIslands().new Solution();
          String data = "[[\"1\",\"1\",\"1\",\"1\",\"0\"],[\"1\",\"1\",\"0\",\"1\",\"0\"],[\"1\",\"1\",\"0\",\"0\",\"0\"],[\"0\",\"0\",\"0\",\"0\",\"0\"]]";
         Character[][] characters = ArrayUtil.StrToCharacterArray(data);

         System.out.println(solution.numIslands(characters));
     }

//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {

    public int numIslands(Character[][] grid) {

        int len = grid.length;
        int res = 0 ;
        for (int i = 0; i < len; i++) {
            int l = grid[i].length;
            for (int i1 = 0; i1 < l; i1++) {
                if (grid[i][i1] == '1'){
                    /**/
                    low(i, i1, grid,1);
                    res++;
                }
            }
        }

        return res;

    }

    //输入:grid = [
//  ["1","1","1","1","0"],
//  ["1","1","0","1","0"],
//  ["1","1","0","0","0"],
//  ["0","0","0","0","0"]
//]
    public void low(int y , int x,Character[][] grid,int move){

        int r = x;
        int l = y;

        int length = grid[l].length;
        int len = grid.length;
        grid[l][r] = '0' ;

        String lev = "";
        for (Integer i = 0; i < leve; i++) {
            lev += "\t";
        }
        System.out.println(lev+"调用了第"+ ++leve +"层low函数 | 参数 l r "+l+" "+r);
        for (int i = 0; i < len; i++) {
            int length1 = grid[i].length;
            System.out.print(lev);
            for (int i1 = 0; i1 < length1; i1++) {
                System.out.print(  grid[i][i1]+" ");
            }
            System.out.println();
        }
        System.out.println();

        /*右*/
        while( r+1 < length && grid[l][r+1] == '1'&& ! (move == 2) ){
            low(l , ++r,grid,1);
        }
        r = x;

        /*左*/
        while(0<= r-1 && grid[l][r-1] == '1'&& !(move == 1)  ){
            low(l , --r,grid,2);
        }
        r = x;

        /*上*/
        while(0<= l-1 && grid[l-1][r] == '1'&& !(move == 3)   ){
            low(--l , r,grid,4);
        }
        l = y;
        /*下*/
        while(l+1 < len && grid[l+1][r] == '1'&& !(move == 4)   ){
            low(++l , r,grid,3);
        }
        l = y;

        System.out.println(lev+"退出了第"+ leve-- +"层low函数 | 参数 l r "+l+" "+r);
        for (int i = 0; i < len; i++) {
            int length1 = grid[i].length;
            System.out.print(lev);
            for (int i1 = 0; i1 < length1; i1++) {
                System.out.print(  grid[i][i1]+" ");
            }
            System.out.println();
        }
        System.out.println();

    }

}
//leetcode submit region end(Prohibit modification and deletion)

}

6 完成

附上我的AC给大家沾沾喜气吧,虽然耗时和内存消耗还比较高,但是很省头发的调试出来了!也祝大家把所有问题AC!有帮助多多点赞收藏哦。

解答成功:
    执行耗时:3 ms,击败了62.98% 的Java用户
    内存消耗:49.7 MB,击败了66.20% 的Java用户

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

babala12 发表于 2023-3-27 18:50
好仔细,学,学
dmxayjn 发表于 2023-3-27 21:03
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止回复与主题无关非技术内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-6-6 01:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表