一次递归带来的的stackOverFlow
来源:互联网 发布:mysql navicat 破解版 编辑:程序博客网 时间:2024/06/01 11:36
现象描述
刚才正在写算法题,运行后,看到了一大堆的红色的控制台输出,以为是程序出现了“索引超出”异常,仔细一看,却是
Exception in thread "main" java.lang.StackOverflowError
.
我的算法代码是
public static void main(String[] args) { int[][]arr={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; print(arr,0,0,arr.length-1,arr[0].length-1); } public static void print(int[][] arr,int x1, int y1, int x2, int y2 ) { for(int i=x1;i<x2;i++) { System.out.print(arr[y1][i]+" "); } for(int i=y1;i<y2;i++){ System.out.print(arr[i][x2]+" "); } for(int i=x2;i>x1;i--){ System.out.print(arr[y2][i]+" "); } for(int i=y2;i>y1;i--){ System.out.print(arr[i][x1]+" "); } print(arr, x1+1, y1+1, x2-1, y2-1); }
Exception in thread "main" java.lang.StackOverflowError
出现的原因
这种情况的出现可能是eclipse智障了吧(平时项目用的都是idea,只有在做算法题目时偶尔用eclipse),那我就把这种情况当成是项目中出现的问题吧,从头来解决一下,毕竟在面试的时候,就有面试官问道了递归算法可能会带来什么问题
,就是StackOverflowErro
咯。
解决步骤1:检查是不是代码不能正常结束
修改后的main方法如下面的代码所示:
public static void main(String[] args) { int[][]arr={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; print(arr,0,0,arr.length-1,arr[0].length-1); System.out.println("程序可以输出这句话,因为此程序可以正常结束");}
执行,看控制台输出
发现真的可能是我的问题,我程序中用到了递归了。。。。。。。。。。那应该是我们的递归没有终止条件咯吧。。。
解决步骤2:修改print
方法
经过分析,我发现我在原来的print方法最后的地柜调用中,没有判断x2<x1
以及y2<y1
.那在print方法的头部进行判断,修改后的代码如下所示:
public static void print(int[][] arr,int x1, int y1, int x2, int y2 ) { if(x2<x1 ||y2<y1 ){ return; } for(int i=x1;i<x2;i++) { System.out.print(arr[y1][i]+" "); } for(int i=y1;i<y2;i++){ System.out.print(arr[i][x2]+" "); } for(int i=x2;i>x1;i--){ System.out.print(arr[y2][i]+" "); } for(int i=y2;i>y1;i--){ System.out.print(arr[i][x1]+" "); } print(arr, x1+1, y1+1, x2-1, y2-1);}
程序运行结果如下图所示:
可以看到现在程序是可以正常结束的了。
继续扯:如何将递归程序编写非递归
可以看到上面的print
方法在自身的最后一行代码调用了自身,这是一种尾递归的写法。上次阿里巴巴的老师问我是不是所有的地柜都可以用非递归的方法来实现
,我回答可以
,然后老师就让我了解一下尾递归
,我当时以为是伪递归
。。。
什么是伪递归
顾名思义,尾递归就是从最后开始计算, 每递归一次就算出相应的结果, 也就是说, 函数调用出现在调用者函数的尾部, 因为是尾部, 所以根本没有必要去保存任何局部变量. 直接让被调用的函数返回时越过调用者, 返回到调用者的调用者去。尾递归就是把当前的运算结果(或路径)放在参数里传给下层函数,深层函数所面对的不是越来越简单的问题,而是越来越复杂的问题,因为参数里带有前面若干步的运算路径。
尾递归是极其重要的,不用尾递归,函数的堆栈耗用难以估量,需要保存很多中间函数的堆栈。比如
f(n, sum) = f(n-1) + value(n) + sum;
会保存n个函数调用堆栈,而使用尾递归
f(n, sum) = f(n-1, sum+value(n));
这样则只保留后一个函数堆栈即可,之前的可优化删去。
关于所有的尾递归是否都可以用非递归的方法来实现
,我目前还是没有找到一个准确的答案,下面给一个知乎上轮子哥(vczh)
参与的一个讨论吧,地址如下:enter description here
那上面的代码我还是用非递归来实现一下吧
public static void printUnRec(int[][] arr) { int x1 = 0, y1 = 0, x2 = arr.length - 1, y2 = arr[0].length - 1; while (x2 >=x1 && y2 >= y1) { for (int i = x1; i < x2; i++) { System.out.print(arr[y1][i] + " "); } for (int i = y1; i < y2; i++) { System.out.print(arr[i][x2] + " "); } for (int i = x2; i > x1; i--) { System.out.print(arr[y2][i] + " "); } for (int i = y2; i > y1; i--) { System.out.print(arr[i][x1] + " "); } x1++; y1++; x2--; y2--; }}
程序的运行结果
嗯,是我智障了,不是eclipse智障。
那我们在写递归算法的时候,是不是要仔细检查递归终止条件呢。。。
- 一次递归带来的的stackOverFlow
- GOOGLE带来的可能是一次革命
- GOOGLE带来的可能是一次革命
- 一次错误估算带来的启示
- 一次函数默认值带来的问题
- 一次排队就餐带来的思考
- 中国的stackoverflow
- StackOverFlow提问的艺术
- 一次跳槽的经历带来的一些感悟。
- 更改Ubuntu用户名带来的一次惊心动魄的经历
- Android 2.3 StackOverflow的解决方案
- [stackoverflow]哈希表是如何工作的?
- StackOverflow的2015开发者调查
- stackoverflow那些有趣的badges
- C#中关于new关键字带来的无限递归错误
- 带来的
- 一次上机面试题带来的感悟【学习的感觉、学习的方法】
- 自己的stackoverflow的账号信息
- Lua和C++交互详细总结
- Android Studio集成NDK开发环境
- JAVA基础
- UESTC 844 程序设计竞赛 【维护值稍多的线段树】
- 响应式布局开发 -3
- 一次递归带来的的stackOverFlow
- Java垃圾收集算法
- java之匿名内部类中的多态
- JVM使用SIGSEGV优化空值检测
- Struts2的配置 struts.xml Action详解
- C语言中如何计算时间差 秒
- A
- Linux下配置iptables实现外网访问内网KMS服务器
- 开发需要关注的几个层面