【问题标题】:Get the level of a node in a tree using JgraphT使用 JgraphT 获取树中节点的级别
【发布时间】:2018-04-20 19:49:33
【问题描述】:

我正在使用 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 方式遍历图形时,如何使用其级别标记每个节点?

【问题讨论】:

  • 更新了我的答案:JGraphT 现在在 BFS 迭代器中有一个 getDepth(V v) 方法。要么从 Maven 下载最新的快照版本,要么等到今年晚些时候的下一个稳定版本。不要忘记投票。
  • getDepth() 方法似乎提供了最短的深度。如果您想要最长的深度,则需要另一种方法。

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


【解决方案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)));

        }
    }
}

底部的 main 函数执行您的示例。输出是:

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

显然,您必须做一些工作才能获得阵列,但这应该从这里开始。两句话:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多