使用JgraphT获取树中节点的级别

时间:2018-04-20 19:49:34

标签: tree graph-theory breadth-first-search jgrapht

我正在使用jGraphT数据结构,我希望能够创建按树中的级别分组的对象列表的ArrayList。

这里是图表

Graph<Obj, DefaultEdge> serviceGraph =
        new DefaultDirectedGraph<>(DefaultEdge.class);




    serviceGraph.addVertex(a);
    serviceGraph.addVertex(b);
    serviceGraph.addVertex(c);
    serviceGraph.addVertex(d);
    serviceGraph.addVertex(e);
    serviceGraph.addVertex(z);


    serviceGraph.addEdge(a, b);
    serviceGraph.addEdge(b, c);
    serviceGraph.addEdge(b, z);
    serviceGraph.addEdge(b, d);
    serviceGraph.addEdge(d, e);

我可以使用BFSIterator遍历图表,如下所示

A
B
C
Z
D
E

这是我想要的顺序,但我也想知道每个节点的级别,以便我可以将它们分组为

[(A), (B), (C,D,Z) ,(E)]

我在DirectedGraph API中找不到任何可以轻松获得关卡的内容。当我以BFS方式遍历图形时,如何用其级别标记每个节点?

1 个答案:

答案 0 :(得分:1)

编辑:JGraphT现在支持这些功能。使用BFS迭代器,您可以使用getDepth(V v)方法查询顶点的深度。

============ 旧答案(这几乎是如何实现的):

目前此功能不可用。但是,正在其中一个Pull Requests中进行处理。这个PR可能需要几个月的时间才能合并。然而,与此同时,这个功能相当容易添加。我已经实现了一个新的BFSIterator,它只是对现有BFSIterator的修改。

package org.jgrapht.traverse;

import org.jgrapht.Graph;
import org.jgrapht.Graphs;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * A breadth-first iterator for a directed or undirected graph which supports querying the depth of a vertex
 * in the search tree.
 * 
 * <p>
 * For this iterator to work correctly the graph must not be modified during iteration. Currently
 * there are no means to ensure that, nor to fail-fast. The results of such modifications are
 * undefined.
 *
 * @param <V> the graph vertex type
 * @param <E> the graph edge type
 *
 * @author Joris Kinable
 * @since April 21, 2018
 */
public class BreadthFirstIteratorWithLevel<V, E>
    extends CrossComponentIterator<V, E, Integer>
{
    private Deque<V> queue = new ArrayDeque<>();

    /**
     * Creates a new breadth-first iterator for the specified graph.
     *
     * @param g the graph to be iterated.
     */
    public BreadthFirstIteratorWithLevel(Graph<V, E> g)
    {
        this(g, (V) null);
    }

    /**
     * Creates a new breadth-first iterator for the specified graph. Iteration will start at the
     * specified start vertex and will be limited to the connected component that includes that
     * vertex. If the specified start vertex is <code>null</code>, iteration will start at an
     * arbitrary vertex and will not be limited, that is, will be able to traverse all the graph.
     *
     * @param g the graph to be iterated.
     * @param startVertex the vertex iteration to be started.
     */
    public BreadthFirstIteratorWithLevel(Graph<V, E> g, V startVertex)
    {
        super(g, startVertex);
    }

    /**
     * Creates a new breadth-first iterator for the specified graph. Iteration will start at the
     * specified start vertices and will be limited to the connected component that includes those
     * vertices. If the specified start vertices is <code>null</code>, iteration will start at an
     * arbitrary vertex and will not be limited, that is, will be able to traverse all the graph.
     *
     * @param g the graph to be iterated.
     * @param startVertices the vertices iteration to be started.
     */
    public BreadthFirstIteratorWithLevel(Graph<V, E> g, Iterable<V> startVertices)
    {
        super(g, startVertices);
    }

    /**
     * @see CrossComponentIterator#isConnectedComponentExhausted()
     */
    @Override
    protected boolean isConnectedComponentExhausted()
    {
        return queue.isEmpty();
    }

    /**
     * @see CrossComponentIterator#encounterVertex(Object, Object)
     */
    @Override
    protected void encounterVertex(V vertex, E edge)
    {
        int depth= (edge == null ? 0 : getSeenData(Graphs.getOppositeVertex(graph, edge, vertex))+1);
        putSeenData(vertex, depth);
        queue.add(vertex);
    }

    /**
     * @see CrossComponentIterator#encounterVertexAgain(Object, Object)
     */
    @Override
    protected void encounterVertexAgain(V vertex, E edge)
    {
    }

    /**
     * @see CrossComponentIterator#provideNextVertex()
     */
    @Override
    protected V provideNextVertex()
    {
        return queue.removeFirst();
    }

    public int getDepth(V v){
        assert getSeenData(v) != null;
        return getSeenData(v);
    }

    public static void main(String[] args){
        Graph<String, DefaultEdge> serviceGraph =
                new DefaultDirectedGraph<>(DefaultEdge.class);
        serviceGraph.addVertex("a");
        serviceGraph.addVertex("b");
        serviceGraph.addVertex("c");
        serviceGraph.addVertex("d");
        serviceGraph.addVertex("e");
        serviceGraph.addVertex("z");


        serviceGraph.addEdge("a", "b");
        serviceGraph.addEdge("b", "c");
        serviceGraph.addEdge("b", "z");
        serviceGraph.addEdge("b", "d");
        serviceGraph.addEdge("d", "e");

        BreadthFirstIteratorWithLevel<String, DefaultEdge> bfs=new BreadthFirstIteratorWithLevel<String, DefaultEdge>(serviceGraph);
        while (bfs.hasNext()) {
            String vertex=bfs.next();
            System.out.println(String.format("Vertex: %s, depth: %s",vertex, bfs.getDepth(vertex)));

        }
    }
}

底部的主要功能执行你的例子。输出是:

Vertex: a, level: 0
Vertex: b, level: 1
Vertex: c, level: 2
Vertex: z, level: 2
Vertex: d, level: 2
Vertex: e, level: 3

显然,你必须做一些工作来获得你的阵列,但这应该是从这里直接进行的。两句话:

  • 此代码未在您的小例子之外进行测试,因此可能会被错误地
  • 在迭代器返回顶点后,您只能 查询顶点的深度。