我有一個遞歸調用自己的函數,我想檢測並終止,如果進入一個無限循環,即 - 再次調用相同的問題。什麼是最簡單的方法來做到這一點?如何檢測遞歸調用中的無限循環?
編輯:這是函數,它將被遞歸調用x和y的不同值。如果在遞歸調用中,我想要終止對(x,y)的值。
int fromPos(int [] arr, int x, int y)
我有一個遞歸調用自己的函數,我想檢測並終止,如果進入一個無限循環,即 - 再次調用相同的問題。什麼是最簡單的方法來做到這一點?如何檢測遞歸調用中的無限循環?
編輯:這是函數,它將被遞歸調用x和y的不同值。如果在遞歸調用中,我想要終止對(x,y)的值。
int fromPos(int [] arr, int x, int y)
如果功能純粹是功能性的,也就是沒有狀態或副作用,那麼你可以保留的參數的Set
(編輯:看到你的編輯,你會保持一個集對的(X, y))它已被調用,並且每次只檢查當前參數是否在集合中。這樣,如果你很快遇到它,你可以檢測到一個循環。但是如果參數空間很大並且需要很長時間才能重複,那麼在檢測到一個循環之前,可能會耗盡內存。一般來說,你不能這樣做,因爲這是停滯的問題。
的一種方法是從一個電話傳遞一個depth
變量到下一個,遞增每個函數調用自身一次。檢查depth
不會超過某個特定的閾值。例如:
int fromPos(int [] arr, int x, int y)
{
return fromPos(arr, x, y, 0);
}
int fromPos(int [] arr, int x, int y, int depth)
{
assert(depth < 10000);
// Do stuff
if (condition)
return fromPos(arr, x+1, y+1, depth + 1);
else
return 0;
}
一個簡單的方法是執行下列操作之一:
以前的值和新的值傳遞給遞歸調用,讓你的第一步檢查,看他們是否相同 - 這可能是你的遞歸情況。
傳遞一個變量來表示該函數被調用的次數,並且任意限制它可以被調用的次數。
如果你想保留你的方法簽名,你可以保留幾組記錄x和y的舊值。
static Set<Integer> xs;
static Set<Integer> ys;//Initialize this!
static int n=0;//keeps the count function calls.
int fromPos(int [] arr, int x, int y){
int newX= getX(x);
int newY= getY(y);
n++;
if ((!xs.add(Integer.valueOf(newX)) && !ys.add(Integer.valueOf(newY))){
assert(n<threshold); //threshold defined elsewhere.
fromPos(arr,newx,newy);
}
}
看起來你可能正在處理2D數組。如果你在數組的值中有多餘的餘數,你可以用它作爲標誌。檢查它,如果標誌已經設置,則終止遞歸。然後在繼續之前設置它。
如果您在值中沒有多餘空間,您可以始終使其成爲一個對象數組。
您只能使用程序分析來檢測最不重要的程序。你所能做的最好的就是在你的特定情況下加入警衛,並通過深度級別的背景。檢測一般情況並區分遞歸算法的合法使用幾乎是不可能的。
您需要找到解決辦法,因爲正如您所問,沒有通用的解決方案。有關更多信息,請參閱Halting problem。
您可以使用重載的一致的簽名(這是更好的方法),也可以使用一個靜態變量:
int someFunc(int foo)
{
static recursionDepth = 0;
recursionDepth++;
if (recursionDepth > 10000)
{
recurisonDepth = 0;
return -1;
}
if (foo < 1000)
someFunc(foo + 3);
recursionDepth = 0;
return foo;
}
約翰Kugelman與超載答案是更好的怎麼一回事,因爲它是線程安全的,而靜態變量不是。
Billy3
恕我直言只有循環可以進入一個無限循環。
如果你的方法有太多的遞歸級別,JVM會拋出一個StackOverflowError。您可以使用try/catch塊捕獲此錯誤,並在出現此情況時執行您計劃執行的任何操作。
該死!你打敗了我! – 2009-06-23 03:46:32
+1也打我。 – Tom 2009-06-23 03:47:36
我寧願如果方法簽名保持不變。 – Pranav 2009-06-23 03:49:17