Java:向图形bug添加节点

时间:2009-11-16 23:01:40

标签: java graph

前言:我知道有高质量的图形API可用。我有兴趣写自己的自我改进。

这是我添加节点的功能:

    public void addNode(Vertex v, Collection<Edge> neighbors) {

        int originalSize = size();

        if (head == null) {
            head = v;
        }
        else {
            Collection<Edge> inEdges = new ArrayList<Edge>();
            inEdges.addAll(neighbors);

            traverseGraphToAdd(head, inEdges, v);
        }

        assert originalSize + 1 == size() : 
                        String.format("adding operation failed. original size: %d, current size: %d", originalSize, size());
    }
private void traverseGraphToAdd(Vertex start, Collection<Edge> inEdges, Vertex toAdd) {
        Iterator<Edge> iter = inEdges.iterator();
        Edge e;
        while (iter.hasNext()) {
            e = iter.next();
            if (e.getSource().equals(start)) {
                start.addEdge(e);
                iter.remove();
            }
            else if (! directionalEdges && e.getSink().equals(start)) {
                start.addEdge(e);
                iter.remove();
            }
        }
        if (inEdges.size() > 0) { //otherwise there's no point in continuing to search
            for (Edge arc : start.getOutEdges()) {
                traverseGraphToAdd(arc.getSink(), inEdges, toAdd);
            }
        }
    }

大小及其依赖项:

public int size() {
    int count = 0;
    if (head == null) {
        return 0;
    }
    else {
        count = countNodes(head);
    }
    clearVisited();
    return count;
}

private int countNodes(Vertex start) {
    int result = 1;
    start.setVisited(true);
    for (Edge e: start.getOutEdges()) {
        if (! e.getSink().isVisited()) {
            result += countNodes(e.getSink());
        }
    }
    return result;
}

private void clearVisited() {
    if (head != null) {
        clearNode(head);
    }
}

private void clearNode(Vertex start) {
    start.setVisited(false);
    for (Edge e: start.getOutEdges()) {
        if (e.getSink().isVisited()) {
            clearNode(e.getSink());
        }
    }
}

Edge类:

public Edge(Vertex source, Vertex sink, int weight) {
    this.source = source;
    this.sink = sink;
    this.weight = weight;
}

以下调用有效:

g.addNode(ftw, new HashSet<Edge>()); //first node - empty edges
g.addNode(odp, Arrays.asList(new Edge(ftw, odp, 3))); //link new node to one already in the graph

这不是:

g.addNode(tlt, Arrays.asList(new Edge(tlt, ftw, 2)));

在这一个中,Edge构造函数的第一个参数是图中已有的节点。我尝试使用以下内容(从上面重复)在addNode中纠正此问题:

if (e.getSource().equals(start)) { /*... */ }
else if (! directionalEdges && e.getSink().equals(start)) { /*... */ }

directionalEdges是一个类字段,用于确定此图形是否具有方向性。

但是,这会导致断言错误:

Exception in thread "main" java.lang.AssertionError: adding operation failed. original size: 1, current size: 1

这里发生了什么?

1 个答案:

答案 0 :(得分:0)

您尝试在示例中创建的图表如下所示:

tlt -> ftw -> odp

创建ftw -> odp后,您应该(并且我相信)拥有head == ftw。添加tlt后,如果您希望遍历算法正常运行,则应该head == tlt。但是在您向我们展示的代码中,只有一个地方head被分配,而这只发生在head == null的条件下,在addNode()的第五行。因此,当您添加head时,tlt不会更改,因此traverseGraphToAdd()因此会以ftw而不是tlt的形式开始。

但是,这里有一个更普遍的问题,即你的代码无法处理没有root的有向图(也就是说,它们有多个源节点。)考虑如果你想要的话会发生什么像这样的图表:

a -> b <- c

我认为你有这个问题,因为你不再只有一个人。