1

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

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

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

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 级更深,根据我的逻辑它不会捕获它。还有其他方法吗?

提前致谢!

4

2 回答 2

4

还有其他方法吗?

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

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

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

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

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


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

于 2013-02-02T04:43:00.987 回答
0

感谢@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;
}
于 2013-02-03T06:31:56.270 回答