【问题标题】:Stack Overflow Error on recursion java递归java中的堆栈溢出错误
【发布时间】:2016-12-30 03:14:36
【问题描述】:

我需要找到数组中数字之间的最长路径(从大到小)。 我尝试编写recursive 函数并得到java.lang.StackOverflowError,但由于缺乏知识,我不明白为什么会这样。

首先,我初始化了数组并用随机数填充它:

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

然后,我尝试找到最长的倒数路线(例如 { 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;
}

所以这里是日志:

 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)

感谢任何解释,因为所有相关问题都没有帮助我。如果我的功能有问题,请指正或解释。

编辑

我忘了说,我使用for 来检查每个“点”的最长路径

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

【问题讨论】:

  • start++ 返回start 的原始值,并在之后start 加1。 ++start 将 1 加到 start 之前返回值。
  • 你应该添加一个 Log.i("Start", start.toString());将您的 find 方法作为第一行,这样您就可以看到会发生什么。

标签: java recursion stack-overflow


【解决方案1】:

首先改变

find(route, start++)

find(route, start+1)

由于后自增返回变量的原始值,所以递归永远不会前进,导致StackOverflowError

您还应该添加一个停止条件,否则您的下一个异常将是ArrayIndexOutOfBoundsException

正如 Kevin 所说,您还应该对 find(route, start++); 返回的值做一些事情。否则根本没有必要调用它。

除了这些问题,你的逻辑是错误的。该方法将返回从数组开头开始的降序序列的最后一个索引,它不会告诉您关于最长降序序列的任何信息。例如,对于{ 1, 4, 6, 20, 19, 16, 10, 6, 4, 7, 6, 1 ...},您的方法将返回0(数组的第一个索引),因为route[0] &gt; route[1] 为假。

【讨论】:

  • 他也应该在那里返回find
【解决方案2】:

您需要保持到现在为止的当前最大值和当前值。 所以修改如下:

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);
}

并以开头来调用它

find(route, 0, 1, 0);

第二种选择是不递归地重写它:

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;
}

并将其称为

find(route);

【讨论】:

  • 请注意,这段代码只是一个起点。您需要处理空路由数组,例如空路由数组。
【解决方案3】:

当您调用 start++ 时,您将执行 后增量。这意味着操作发生在将参数传递给方法之后 - 这意味着您的方法只是在第一个参数上不断循环,直到内存耗尽。 将其替换为 start+1,您将获得一大堆新的异常来玩 ;)

【讨论】:

    【解决方案4】:

    其他用户在此处指出的算法存在几个问题。但主要问题是这个算法不能是递归的。递归只能找到从零索引开始的降序序列的长度。

    一个正确的算法必须贯穿整个数组:

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-10
      • 2014-08-27
      • 2016-11-11
      • 1970-01-01
      • 1970-01-01
      • 2015-12-08
      • 2015-06-17
      • 1970-01-01
      相关资源
      最近更新 更多