java - 关于递归的常见行业惯例是什么?或者我们怎么知道我们是否应该完全避免递归?
问题描述
我确实理解递归的问题之一是堆栈深度,它可能导致非常深的递归问题。此外,我知道递归可以用显式堆栈使用来代替,以避免此类问题。
另一方面,如果我没记错的话,递归允许代码简洁明了(我会说很漂亮),并且是在所有标准教科书中呈现算法的主要方式。
我的问题比理论更实际:
我正在运行以下程序来弄清楚在我得到一个之前我能走多远java.lang.StackOverflowError
我的理由是,例如,如果我有一个小的图形视图,有几千个顶点并且每次遍历的处理最少,那么递归与迭代方法可能无关紧要:
public static void foo(int i) {
if (i % 5000 == 0) {
System.out.println(i);
}
foo(i + 1);
}
public static void main(String[] args) {
foo(0);
}
输出是:
Exception in thread "main" java.lang.StackOverflowError
5000
10000
因此,我的解释是,程序会在处理超过 10000 个顶点后进行 DFS,这听起来很小。
谷歌搜索我发现当我们运行一个程序时,堆栈的默认大小是可以配置的,但我想知道这个行业的惯例是什么?
是否为重型服务器程序设置显式线程堆栈大小,以便上面的示例在实践中不会成为问题?还是完全避免编写递归?还是我的例子不能真正代表一个问题?
更新
我明白上面的代码示例是一个无限递归。这样做的唯一目的是看看它在断裂之前能走多远。
解决方案
是否为重型服务器程序设置显式线程堆栈大小,以便上面的示例在实践中不会成为问题?
不。
- 例子是无限递归。这将永远是一个问题。
- Java 中没有足够大的堆栈大小。它需要无限量的堆栈空间。
- (在实现“尾调用优化”的语言/实现中,不会出现堆栈溢出。但 Java 不是这样的语言。)
还是完全避免编写递归?
不,递归很好……只要你能预测递归的最大深度。
还是我的例子不能真正代表一个问题?
它并没有真正的代表性。
然而,现实世界中显然存在一些问题,其中递归方法对于某些输入会失败。
谷歌搜索我发现当我们运行一个程序时,堆栈的默认大小是可以配置的,但我想知道这个行业的惯例是什么?
设置默认堆栈大小没有相关的“行业惯例”。所需的堆栈大小取决于实际算法及其实现以及输入数据。
但是,当您无法对递归深度设置合理的界限时,尝试实现递归解决方案是一个坏主意。
对于给定的 Java 程序,计算给定递归深度所需的堆栈空间在技术上是可行的,但计算将取决于平台。
JVM 对最大堆栈大小进行了限制。例如,对于 64 位模式下 x86-64 上的 Java 11,您不能设置-Xss
大于1g
. (这可能是件好事。)
推荐阅读
- python - 使用 Tweepy 列出直接消息
- spring-boot - 如何在多个微服务的生产者和消费者之间端到端跟踪rabbitmq?
- rust - 有没有办法根据常量的存在有条件地编译?
- feathersjs - Featherjs - 添加自定义字段以挂钩上下文对象
- elasticsearch - 如何让 elasticsearch 5.6.3 跨集群搜索工作?
- regex - 仅显示特定的正则表达式组并使用 sed 在 bash 中删除该行的其余部分
- mysql - MySQL对多个分组的最新值求和
- python - 这是使用 smtplib 的方式吗
- python - Python 序数排名
- node.js - IS LIST 在对话流实现中是否与@sys.any 一起使用?