简体   繁体   English

递归java上的堆栈溢出错误

[英]Stack Overflow Error on recursion java

I need to find the longest way (from bigger to lower) between numbers in array. 我需要找到数组中数字之间最长的方式(从大到小)。 I've tried to write recursive function and got java.lang.StackOverflowError , but for the lack of knowledge I didn't understand why this happened. 我试图编写recursive函数并得到java.lang.StackOverflowError ,但由于缺乏知识,我不明白为什么会发生这种情况。

Firstly, I've initialize array and fill it with random numbers: 首先,我初始化数组并用随机数填充它:

public long[] singleMap = new long[20];
for (int i = 0; i < 20; i++) {
        singleMap[i] = (short) random.nextInt(30);
    }

Then, I try to find the longest route of counting down numbers (eg { 1, 4, 6, 20, 19, 16, 10, 6, 4 , 7, 6, 1 ...} ) and to return the count such numbers. 于是,我试图找到掰着指头数最长的途径(例如{1,4,6,20,19,16,10,6,4,7,6,1 ...})并返回计数等数字。

 public int find(long[] route, int start) {
    if (route[start] > route[start + 1]) {
        find(route, start++);
    } else {
        return start;
    }
    return start;
}

So here's log: 所以这是日志:

 08-23 13:06:40.399 4627-4627/itea.com.testnotification I/dalvikvm:   threadid=1: stack overflow on call to    Litea/com/testnotification/MainActivity;.find:ILI
 08-23 13:06:40.399 4627-4627/itea.com.testnotification I/dalvikvm:   method requires 36+20+12=68 bytes, fp is 0x4189e318 (24 left)
 08-23 13:06:40.399 4627-4627/itea.com.testnotification I/dalvikvm:   expanding stack end (0x4189e300 to 0x4189e000)
 08-23 13:06:40.400 4627-4627/itea.com.testnotification I/dalvikvm: Shrank stack (to 0x4189e300, curFrame is 0x418a3e88)
 08-23 13:06:40.400 4627-4627/itea.com.testnotification D/AndroidRuntime: Shutting down VM
 08-23 13:06:40.400 4627-4627/itea.com.testnotification W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41a8ed40)
 08-23 13:06:40.414 4627-4627/itea.com.testnotification E/AndroidRuntime: FATAL EXCEPTION: main
                                                                         Process: itea.com.testnotification, PID: 4627
                                                                     java.lang.StackOverflowError
                                                                         at itea.com.testnotification.MainActivity.find(MainActivity.java:46)
                                                                         at itea.com.testnotification.MainActivity.find(MainActivity.java:46)

I appreciate any explanation because all related issues didn't help me. 我感谢任何解释,因为所有相关问题都没有帮助我。 If there is a problem in my function, please correct or explain. 如果我的功能有问题,请更正或解释。

EDIT 编辑

I forgot to say, that I use for to check the longest way from each "point" 我忘记说了,我用for从每个“点”的检查方式最长

  for (int i = 0; i < singleMap.length - 1; i++) {
        int x = find(singleMap, i);
        System.out.println("steps = " + x);
    }

First of all change 首先是改变

find(route, start++)

to

find(route, start+1)

since post-increment returns the original value of the variable, so the recursion never advances, leading to StackOverflowError . 因为post-increment返回变量的原始值,所以递归永远不会前进,导致StackOverflowError

You should also add a stopping condition, otherwise your next exception would be ArrayIndexOutOfBoundsException . 您还应该添加一个停止条件,否则您的下一个异常将是ArrayIndexOutOfBoundsException

As Kevin commented, you should also do something with the value returned by find(route, start++); 正如Kevin评论的那样,你也应该对find(route, start++);返回的值做一些事情find(route, start++); . Otherwise there is no point in calling it at all. 否则完全无需调用它。

Besides those issues, your logic is wrong. 除了这些问题,你的逻辑是错误的。 The method will return the last index of the descending sequence starting at the beginning of the array, which tells you nothing about the longest descending sequence. 该方法将返回从数组开头开始的降序序列的最后一个索引,它不会告诉您最长的降序序列。 For example, for { 1, 4, 6, 20, 19, 16, 10, 6, 4, 7, 6, 1 ...} your method would return 0 (the first index of the array), since route[0] > route[1] is false. 例如,对于{ 1, 4, 6, 20, 19, 16, 10, 6, 4, 7, 6, 1 ...}您的方法将返回0 (数组的第一个索引),因为route[0] > route[1]是假的。

You need to mantain the current max find up to now, and the current value. 您需要保留到目前为止的当前最大值,以及当前值。 So change it as follow: 所以改变如下:

public int find(int[] route, int start, int max, int currentMax) {
    if (currentMax > max) {
        max = currentMax;
    }
    if (start == route.length - 1) {
        return max;
    }
    if (route[start] > route[start + 1]) {
        return find(route, start + 1, max, currentMax + 1);
    }
    return find(route, start + 1, max, 1);
}

And call it with a starting 并用一个开始调用它

find(route, 0, 1, 0);

A second alternative is to rewrite it without recursion: 第二种方法是在没有递归的情况下重写它:

public int find(int[] route) {
    int max = 1;
    int currentMax = 1;
    for (int i = 0; i < route.length - 1; i++) {
        if (route[i] > route[i + 1]) {
            currentMax++;    // If next element is lower increment currentMax
            if (currentMax > max) {
                max = currentMax;   // If currentMax is the new max update max
            }

        } else {
            currentMax = 1;   // If next element is not lower restart from 1
        }
    }
    return max;
}

and call it as 并称之为

find(route);

When you call start++ you perform a postincrementation . 当你调用start ++时,你会执行一个postincrementation It means that the operation occurs after passing the parameter to the method - which means that your method just keeps going around in circles on the first parameter until the memory runs out. 这意味着将参数传递给方法之后进行操作 - 这意味着您的方法只是在第一个参数的圆圈中继续运行,直到内存耗尽。 Replace it with start+1 and you'll get the whole new bunch of exceptions to have fun with ;) 用start + 1替换它,你将获得全新的一系列例外以获得乐趣;)

You have several problems in the algorithm that other users pointed here. 您在此算法中遇到了其他用户指出的几个问题。 But the main problem is that this algorithm must not be recursive. 但主要问题是该算法不能递归。 Recursively, you can only find the length of the descending sequence that starts at the zero index. 递归地,您只能找到从零索引开始的降序序列的长度。

A correct algorithm must run through the whole array: 正确的算法必须贯穿整个数组:

public static int find(long[] route) {
    int maxIdx = 0;
    int maxCount = 1;
    for (int i = 1, c = 0; i < route.length; i++) {
        if (route[i] < route[i - 1]) {
            if (++c >= maxCount) {
                maxCount = c;
                maxIdx = i - c;
            }
        } else {
            c = 0;
        }
    }
    return route.length == 0 ? -1 : maxIdx;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM