【问题标题】:Check for infinite calls/recusrive calls algorithm检查无限调用/递归调用算法
【发布时间】:2013-01-17 11:43:02
【问题描述】:

这是我试图解决的问题的一个子集。假设我已经解析了一些代码,现在我正在尝试检查它是否在逻辑上正确。其中一项检查是函数调用不能调用自己或参与另一个相互调用的函数或一个函数的函数相互调用,等等。

我已经解决了这个问题,并且能够轻松地解决对自身的调用和下一级的调用,尽管它可能不是最佳代码。目前,性能不是问题。

这是我编写的逻辑以及一个示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class LoopTest {

    public static void main(String[] args) {
        List<Loop> test = new ArrayList<Loop>();
        test.add(new Loop("Function1",new String[]{"Function2", "Function1"}));
        test.add(new Loop("Function2",new String[]{"Function3", "Function1"}));
        test.add(new Loop("Function3",new String[]{"Function1"}));
        checkLooping(test);
    }

    public static void checkLooping(List<Loop> input) {
        for(Loop main : input) {
            for(int i = 0; i < main.getInputSize(); i++) {
                if(main.getName().equals(main.getInputValue(i))) {
                    System.err.println("Looping condition found at " + main.getName());
                }
                for(Loop inside : input) {
                    for(int j = 0; j < inside.getInputSize(); j++) {
                        if(main.getInputValue(i).contains(inside.getName()) && 
                                main.getName().equals(inside.getInputValue(j))) {
                            System.err.println("Looping condition found between " 
                                    + main.getName() + " and " + inside.getName());
                        }
                    }
                }
            }
        }
    }
}

class Loop {
    private String name;
    private String input[];

    public Loop(String name, String input[]) {
        this.name = name;
        this.input = input;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String[] getInput() {
        return input;
    }
    public void setInput(String[] input) {
        this.input = input;
    }

    public int getInputSize() {
        return input.length;
    }

    public String getInputValue(int i) {
        return input[i];
    }

    public boolean contains(String search) {
        if(name.contains(search))
            return true;
        else
            return false;
    }

    @Override
    public String toString() {
        return String.format("%s %s", this.name, Arrays.toString(input));
    }
}

这不会捕捉到 Function1 存在于 Function3 中。因此,如果它比 1 级更深,根据我的逻辑它不会捕获它。还有其他方法吗?

提前致谢!

【问题讨论】:

    标签: java loops infinite-loop


    【解决方案1】:

    还有其他方法吗?

    是的,这是一个图遍历问题;特别是在(在这种情况下)方法调用的图表中检测循环引用的问题。

    一个简单的算法是这样的:

    def detect_cycle(node, seen={}):
        if seen contains node:
            // found a cycle
        seen.add(node)
        foreach child in node.children:
            detect_cycle(child, seen)
    

    (您不需要显式的图结构来执行此遍历。可以使用相同的方法来遍历/检查由另一个数据结构隐含的图。)

    然而,我们在这里实际做的是检查递归调用。我们将无法区分终止的递归(没问题)和无限递归(不好的)。这是一个非常困难的问题。 (实际上,计算理论说证明终止问题的最一般形式是没有解的。)


    作为一个问题或兴趣 (:-)) 上面的图遍历算法是具有 good 递归的程序示例。但是,要编写一个程序来证明它会终止......并确定它不会终止的理论案例,这将是一项巨大的工作!

    【讨论】:

    • 是的,对这类事物建模的方法是有向图,可以在线性时间内检查循环。参见例如stackoverflow.com/questions/4168/graph-serialization/4577#4577
    • 谢谢!我猜的好处是我正在解析的语言不允许任何递归调用。我的问题是 Java 有什么好的数据结构,或者我应该使用像 JGraph 这样的外部库吗?
    • 您不需要 额外的数据结构。您需要的所有信息都在List&lt;Loop&gt; 数据结构中。如果是 Map&lt;String, Loop&gt; ... 可能会更容易查找。您可能出于其他原因想要更改它。您不需要通用的图形数据结构。你的主要结构是一棵树,至少在你做语法的时候是这样。
    • 我可能无法理解这一点:要实现“foreach child in node.children”。也许,如果通过 Map 实现它会更有意义。
    • 非常感谢@StephenC 的帮助!我已经使用您的伪代码为未来的读者提供了运行代码的答案!
    【解决方案2】:

    感谢@StephenC

    这是我转换为使用 Map 后的运行代码:

    private static Map<String, List<String>> main;
    
    
    // more code from above
    
    
    public void detectCycle(String node, Stack<String> seen) {
            if(seen.contains(node)) {
                System.out.println("found cycle at " + node + " and " + seen.get(seen.size()-1));
                return;
            }
            else 
                seen.push(node);
    
            if(main.get(node) != null && main.get(node).size() != 0) {
                for(int i = 0; i < main.get(node).size(); i++) {
                    detectCycle(main.get(node).get(i), seen);
                }
            }
    
            if(!seen.isEmpty())
                seen.pop();
            return;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      相关资源
      最近更新 更多