Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)

(补充:第二种方法:递归算法实现99乘法表|再补充:解析递归算法)

原理:两次循环嵌套+适当换行

正确版:

    public static void main(String[] args)
    {
        int x,y;
        for(x = 1;x <= 9;x++){
            for (y = 1;y <= x;y++){
                System.out.print(y+"*"+x+"="+x*y+"\t");
            }
            System.out.println();
        }
    }
}

Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第1张图片
非正版:

public static void main(String[] args)
    {
        int x,y;
        for(x = 1;x <= 9;x++){
            for (y = 1;y <= x;y++){
                System.out.println(y+"*"+x+"="+x*y+"\t");
            }
            System.out.println();
        }
    }

Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第2张图片
原因:没有正确的换行
System.out.println()
替换为System.out.print()



补充

### 递归算法99乘法表 递归算法是一种直接或间接地 调用自身的算法
public class DikuiTest {

    public static void main(String[] args) {
        m(9);
    }

    public static void m(int i){
        if (i == 1) {
            System.out.println("1*1=1");
        }else {
            m(i - 1);
            for(int j = 1;j <= i;j++){
                System.out.print(j+"*"+i+"="+j*i+" ");
            }
            System.out.println();
        }
    }
}

输出结果:

1*1=1
1*2=2 2*2=4 
1*3=3 2*3=6 3*3=9 
1*4=4 2*4=8 3*4=12 4*4=16 
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 
  • 简单分析:
    1 通过debug发现,程序第一次运行至断点处,(断点打在m(i)方法处)
    Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第3张图片
    2 此时会再次执行m()方法,i减1,控制台没有输出,继续执行,此时i=8
    3 一直运行到i的值变为1,控制台会输出if(i = 1)中的输出语句,1 * 1 = 1(如下图)

    Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第4张图片
    4 神奇的事要发生了(i开始自增,并开始输出语句)
    Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第5张图片
    Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第6张图片

跟踪源码发现看不懂,作为新手菜鸟也很纠结为什么这样…如果那个大神知道请告知



再补充

经过查资料和大神的指导,有了初步的理解.

大神在这

递归的方式调用图示:
Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第7张图片
每一个方法的调用都会产生一个栈帧,压入到方法栈,当递归调用的时候,方法栈中栈帧的图示和上图类似。
去掉方法中栈帧的引用关系更加直观:如下图所示:
Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第8张图片

简化掉相应的方法调用最后执行情况如上图所示,注意 i 一直在变 j每次都是从1开始 然后递增到和i相等。
这样上图依次出栈后就得到了 99 乘法表.

总结:嵌套for循环 和 用递归实现 的比较:栈 主要是用来存放栈帧的,每执行一个方法就会出现压栈操作,所以采用递归的时候产生的栈帧比较多,递归就会影响到内存,非常消耗内存,而使用for循环就执行了一个方法,压入栈帧一次,只存在一个栈帧,所以比较节省内存。

自己的理解

Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第9张图片

  • 类由类加载器加载进内存中,方法被存放在栈中
    • (Java栈也是每个线程单独拥有,线程启动时创建。这个栈中存放着一系列的栈帧(Stack Frame),JVM只能进行压入(Push)和弹出(Pop)栈帧这两种操作。每当调用一个方法时,JVM就往栈里压入一个栈帧,方法结束返回时弹出栈帧)
  • 当m=9第一次进入方法时,if判断为else,
  • 然后执行m(i-1)方法即又调用m方法,此时参数为8,但同时for循环也被加载进栈中.也就是说 m方法执行一次就会往栈中压入(Push)一个栈帧.但是m(i-1)方法没有结束,那么压进栈中的for循环就无法执行.从i=9开始,直到i=1.此时把if判断压入栈中,并执行了if判断中的输出语句.此时压如栈中的for循环为8个,如图:
    :Java程序9 X 9乘法表(补:第二种方法:递归算法实现99乘法表|再补:解析递归算法)_第10张图片

  • 然后按照从上往下,依次取出(弹出Pop)栈帧中的数据执行for循环,直至结束.

    另外:

  • 如果没有if判断的话,在方法中直接调用m(i-1)方法,然后进行for循环操作,如下
public class DikuiTest {

    public static void main(String[] args) {
        m(9);
    }

    public static void m(int i){
            m(i - 1);
            for(int j = 1;j <= i;j++){
                System.out.print(j+"*"+i+"="+j*i+" ");
            }
            System.out.println();
        }
    }

输出:

Exception in thread "main" java.lang.StackOverflowError
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)
    at com.qiushiju.DikuiTest.m(DikuiTest.java:11)

如上,出现堆栈溢出错误.递归无限调用,没写写递归退出的条件.就会一直调用方法,向java虚拟机栈中无限压入栈帧,导致内存溢出.

你可能感兴趣的:(Java基础)