如何在递归调用中检测无限循环?

时间:2009-06-23 03:41:49

标签: java detection infinite-loop

我有一个递归调用自身的函数,我想检测并终止,如果进入一个无限循环,即 - 再次调用相同的问题。最简单的方法是什么?

编辑:这是函数,它将以不同的x和y值递归调用。我想终止,如果在递归调用中,重复对(x,y)的值。

int fromPos(int [] arr, int x, int y)

11 个答案:

答案 0 :(得分:20)

一种方法是将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;
}

答案 1 :(得分:9)

如果函数纯粹是功能性的,即它没有状态或副作用,那么你可以保留Set个参数(编辑:看到你的编辑,你会保留一组对(x, y))它已被调用,并且每次只检查当前参数是否在集合中。这样,如果您很快遇到它,就可以检测到一个循环。但是如果参数空间很大并且需要很长时间才能重复,那么在检测到循环之前可能会耗尽内存。当然,一般情况下,你不能这样做,因为这是暂停问题。

答案 2 :(得分:3)

您需要找到一种解决方法,因为正如您所问,它没有通用解决方案。有关详细信息,请参阅Halting problem

答案 3 :(得分:2)

一种简单的方法是实现以下之一:

将先前的值和新值传递给递归调用,并检查第一步是否相同 - 这可能是您的递归情况。

传递一个变量来表示调用该函数的次数,并任意限制它被调用的次数。

答案 4 :(得分:2)

您只能使用程序分析检测最简单的那些。您可以做的最好的事情是在您的特定环境中添加警卫并传递深度级别背景。几乎不可能检测到一般情况并区分递归算法的合法使用。

答案 5 :(得分:1)

您可以使用重载来获得一致的签名(这是更好的方法),也可以使用静态变量:

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

John Kugelman对重载的回答更好,因为它的线程安全,而静态变量不是。

Billy3

答案 6 :(得分: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);
 }
}

答案 7 :(得分:0)

看起来您可能正在处理2D阵列。如果您在数组的值中有一些额外的位,则可以将其用作标志。检查它,如果已设置标志,则终止递归。然后在继续之前设置它。

如果你没有多余的值,你总是可以把它变成一个对象数组。

答案 8 :(得分:0)

IMHO只有循环可以进入无限循环。

如果您的方法具有太多的递归级别,JVM将抛出StackOverflowError。您可以使用try / catch块捕获此错误,并在发生此情况时执行您计划执行的任何操作。

答案 9 :(得分:0)

如果满足条件,则递归函数终止。

示例:

  • 函数的结果为01
  • 达到最大通话次数
  • 结果低于/大于输入值

在您的情况下,条件为([x0,y0] == [xN,yN]) OR ([x1,y1] == [xN,yN]) OR ([xN-1,yN-1] == [xN,yN])

0, 1, ...N是对

的索引

因此,您需要一个容器(矢量,列表,地图)来存储所有先前的对,并将它们与当前对进行比较。

答案 10 :(得分:0)

首先使用mvn findbugs:gui打开gui,该gui指向出现此错误的行。

我也遇到了同样的问题,我通过在循环验证中添加一个布尔变量来解决了这个问题。

--

之前的代码
for (local = 0; local < heightOfDiv; local = local + 200) { // Line under Error
          tileInfo = appender.append(tileInfo).append(local).toString();
          while (true) {
            try {
              tileInfo = appender.append(tileInfo).append(getTheTextOfTheElement(getTheXpathOfTile(incr))).toString();
              incr++;
            } catch (Exception e) {
              incr = 1;
              tileInfo = appender.append(tileInfo).append("/n").toString();
            }
          }

要解决此问题,我刚刚添加了一个布尔变量,并在catch块中将其设置为false。检查一下

for (local = 0; local < heightOfDiv; local = local + 200) {
          tileInfo = appender.append(tileInfo).append(local).toString();
          boolean terminationStatus = true;
          while (terminationStatus) {
            try {
              tileInfo = appender.append(tileInfo).append(getTheTextOfTheElement(getTheXpathOfTile(incr))).toString();
              incr++;
            } catch (Exception e) {
              incr = 1;
              tileInfo = appender.append(tileInfo).append("/n").toString();
              terminationStatus = false;
            }
          }

这是我解决此问题的方法。 希望这会有所帮助。 :)