Java 使用递归的StackOverflowerr
我应该比较递归函数和非递归函数,看看哪一个对于类项目更快。教授还希望我们在迭代数等于101001000时,以毫秒为单位来迭代迭代。我把它全部都工作了,但是在C++中得到了很多麻烦,得到了定时器,所以我转换到java,因为它更容易得到毫秒输出。 但是现在,当我尝试使用任何超过8000的数字时,递归算法产生了一个很大的堆栈溢出错误。有人能给我一些见解吗? 另外:我也不能像在非递归函数中那样在递归函数中执行计时器。我将如何处理这个问题Java 使用递归的StackOverflowerr,java,recursion,Java,Recursion,我应该比较递归函数和非递归函数,看看哪一个对于类项目更快。教授还希望我们在迭代数等于101001000时,以毫秒为单位来迭代迭代。我把它全部都工作了,但是在C++中得到了很多麻烦,得到了定时器,所以我转换到java,因为它更容易得到毫秒输出。 但是现在,当我尝试使用任何超过8000的数字时,递归算法产生了一个很大的堆栈溢出错误。有人能给我一些见解吗? 另外:我也不能像在非递归函数中那样在递归函数中执行计时器。我将如何处理这个问题 public class comparingTimes {
public class comparingTimes {
public static void main(String[] args) {
double num = 10000;
double result;
nonRec(num);
result = rec(num);
System.out.printf("Rec %.0f",(result));
}
public static void nonRec(double num)
{
double resultNum = 1;
double total = 0;
long startTime = System.currentTimeMillis();
long endTime;
for (double i = 1; i < num; i++)
{
total += i * (i+1);
if (i == resultNum)
{
endTime = System.currentTimeMillis();
System.out.printf("Total execution time: %f seconds - num = %.0f%n", (endTime - startTime)/1000.0, i);
resultNum *= 10;
}
}
System.out.printf("NonRec: %.0f%n", total);
}
public static double rec(double num)
{
if (num == 0)
return 0;
else
return num * (num-1) + rec(num-1);
}
}
公共类比较时间{
公共静态void main(字符串[]args){
双数=10000;
双重结果;
nonRec(num);
结果=rec(num);
System.out.printf(“Rec%.0f”,(结果));
}
公共静态无效NOREC(双数值)
{
双结果数=1;
双倍合计=0;
long startTime=System.currentTimeMillis();
长时间;
for(双i=1;i
递归的理想用例是在每个递归级别上大量减少“搜索空间”。例如,考虑一个二进制搜索,其中每个递归级别将剩下的搜索空间减半。
您的特殊问题是,您正试图执行8000个级别的递归,因为每个级别都会简单地递减值。这将需要相当大的堆栈空间
您可以考虑使用-ss
或-oss
选项来增加JVM的堆栈大小(当然,这取决于实现)。但那只能给你买这么多
就整个递归操作的计时而言,我只需将顶级调用之前的时间存储在main()
中,然后将其与顶级调用返回后的时间进行比较,如:
long startTime = System.currentTimeMillis();
result = rec(num);
long endTime = System.currentTimeMillis();
// Now calculate the elapsed time.
无需尝试在递归调用本身中执行
如果要在递归调用中的某些点执行此操作,可以将“全局”计数器变量(递归本身之外的一个,例如类级静态变量)初始化为0,并让递归函数为每个递归级别递增它
然后让它在您感兴趣的点输出时间增量,例如当变量设置为10、100、1000等等。递归的理想用例是在每个递归级别上大量减少“搜索空间”。例如,考虑一个二进制搜索,其中每个递归级别将剩下的搜索空间减半。 您的特殊问题是,您正试图执行8000个级别的递归,因为每个级别都会简单地递减值。这将需要相当大的堆栈空间 您可以考虑使用
-ss
或-oss
选项来增加JVM的堆栈大小(当然,这取决于实现)。但那只能给你买这么多
就整个递归操作的计时而言,我只需将顶级调用之前的时间存储在main()
中,然后将其与顶级调用返回后的时间进行比较,如:
long startTime = System.currentTimeMillis();
result = rec(num);
long endTime = System.currentTimeMillis();
// Now calculate the elapsed time.
无需尝试在递归调用本身中执行
如果要在递归调用中的某些点执行此操作,可以将“全局”计数器变量(递归本身之外的一个,例如类级静态变量)初始化为0,并让递归函数为每个递归级别递增它
然后让它在您感兴趣的点输出时间增量,例如当变量设置为10、100、1000等等。尝试增加时间增量
至于测量时间
public static void main(String[] args) {
double num = 10000;
double result;
long start = System.currentTimeMillis();
nonRec(num);
long finish = System.currentTimeMillis();
System.out.println("Time taken (non-recursive): " + (finish -start));
start = System.currentTimeMillis();
result = rec(num);
finish = System.currentTimeMillis();
System.out.println("Time taken (recursive): " + (finish -start));
System.out.printf("Rec %.0f",(result));
}
试着增加压力
至于测量时间
public static void main(String[] args) {
double num = 10000;
double result;
long start = System.currentTimeMillis();
nonRec(num);
long finish = System.currentTimeMillis();
System.out.println("Time taken (non-recursive): " + (finish -start));
start = System.currentTimeMillis();
result = rec(num);
finish = System.currentTimeMillis();
System.out.println("Time taken (recursive): " + (finish -start));
System.out.printf("Rec %.0f",(result));
}
拥有
==0
总是有风险的,这就是您在这里遇到的问题。将类型更改为int
@BevynQ所有int值都可以用double表示。从表示整数的双精度中减去1不需要舍入。我认为问题更可能是堆栈空间。@Patrica:是的,你是对的。@PatriciaShanahan:总是正确的。恐怕这是你(BevynQ)必须习惯的。1+给Patricia。拥有==0
总是有风险的,这就是你的问题所在。将类型更改为int
@BevynQ所有int值都可以用double表示。从表示整数的双精度中减去1不需要舍入。我认为问题更可能是堆栈空间。@Patrica:是的,你是对的。@PatriciaShanahan:总是正确的。恐怕这是你(BevynQ)必须习惯的。1+致Patricia。只是好奇,教初学者使用递归编写阶乘正确吗?教递归的概念很好,这不是我在生产代码中会做的事情。阶乘是另一个缓慢减少搜索空间的问题。然而,对于阶乘,至少在溢出堆栈之前,您可能会溢出整数:-)递归是一个优雅的工具,但是,与真正的工具(锤子之类的工具)一样,您必须正确地定位作业。没有人想用十字螺丝刀砍倒一棵卡里树。我不知道哪一棵更糟。我宁愿让堆栈溢出,并得到问题的通知。1+用于伟大的讨论@帕西迪