[英]Stack Overflow Error on recursion java
我需要找到數組中數字之間最長的方式(從大到小)。 我試圖編寫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);
}
首先是改變
find(route, start++)
至
find(route, start+1)
因為post-increment返回變量的原始值,所以遞歸永遠不會前進,導致StackOverflowError
。
您還應該添加一個停止條件,否則您的下一個異常將是ArrayIndexOutOfBoundsException
。
正如Kevin評論的那樣,你也應該對find(route, start++);
返回的值做一些事情find(route, start++);
。 否則完全無需調用它。
除了這些問題,你的邏輯是錯誤的。 該方法將返回從數組開頭開始的降序序列的最后一個索引,它不會告訴您最長的降序序列。 例如,對於{ 1, 4, 6, 20, 19, 16, 10, 6, 4, 7, 6, 1 ...}
您的方法將返回0
(數組的第一個索引),因為route[0] > route[1]
是假的。
您需要保留到目前為止的當前最大值,以及當前值。 所以改變如下:
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);
當你調用start ++時,你會執行一個postincrementation 。 這意味着在將參數傳遞給方法之后進行操作 - 這意味着您的方法只是在第一個參數的圓圈中繼續運行,直到內存耗盡。 用start + 1替換它,你將獲得全新的一系列例外以獲得樂趣;)
您在此算法中遇到了其他用戶指出的幾個問題。 但主要問題是該算法不能遞歸。 遞歸地,您只能找到從零索引開始的降序序列的長度。
正確的算法必須貫穿整個數組:
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.