org.jgrapht.traverse.BreadthFirstIterator Maven / Gradle / Ivy
/*
* (C) Copyright 2003-2023, by Barak Naveh and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* See the CONTRIBUTORS.md file distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the
* GNU Lesser General Public License v2.1 or later
* which is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
*
* SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
*/
package org.jgrapht.traverse;
import org.jgrapht.*;
import java.util.*;
/**
* A breadth-first iterator for a directed or undirected graph.
*
*
* 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 the graph vertex type
* @param the graph edge type
*
* @author Barak Naveh
*/
public class BreadthFirstIterator
extends CrossComponentIterator>
{
private Deque queue = new ArrayDeque<>();
/**
* Creates a new breadth-first iterator for the specified graph.
*
* @param g the graph to be iterated.
*/
public BreadthFirstIterator(Graph 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 null
, 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 BreadthFirstIterator(Graph 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 null
, 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 BreadthFirstIterator(Graph g, Iterable startVertices)
{
super(g, startVertices);
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isConnectedComponentExhausted()
{
return queue.isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
protected void encounterVertex(V vertex, E edge)
{
int depth = (edge == null ? 0
: getSeenData(Graphs.getOppositeVertex(graph, edge, vertex)).depth + 1);
putSeenData(vertex, new SearchNodeData<>(edge, depth));
queue.add(vertex);
}
/**
* {@inheritDoc}
*/
@Override
protected void encounterVertexAgain(V vertex, E edge)
{
}
/**
* Returns the parent node of vertex $v$ in the BFS search tree, or null if $v$ is the root
* node. This method can only be invoked on a vertex $v$ once the iterator has visited vertex
* $v$!
*
* @param v vertex
* @return parent node of vertex $v$ in the BFS search tree, or null if $v$ is a root node
*/
public V getParent(V v)
{
assert getSeenData(v) != null;
E edge = getSeenData(v).edge;
if (edge == null)
return null;
else
return Graphs.getOppositeVertex(graph, edge, v);
}
/**
* Returns the edge connecting vertex $v$ to its parent in the spanning tree formed by the BFS
* search, or null if $v$ is a root node. This method can only be invoked on a vertex $v$ once
* the iterator has visited vertex $v$!
*
* @param v vertex
* @return edge connecting vertex $v$ in the BFS search tree to its parent, or null if $v$ is a
* root node
*/
public E getSpanningTreeEdge(V v)
{
assert getSeenData(v) != null;
return getSeenData(v).edge;
}
/**
* Returns the depth of vertex $v$ in the search tree. The depth of a vertex $v$ is defined as
* the number of edges traversed on the path from the root of the BFS tree to vertex $v$. The
* root of the search tree has depth 0. This method can only be invoked on a vertex $v$ once the
* iterator has visited vertex $v$!
*
* @param v vertex
* @return depth of vertex $v$ in the search tree
*/
public int getDepth(V v)
{
assert getSeenData(v) != null;
return getSeenData(v).depth;
}
/**
* @see CrossComponentIterator#provideNextVertex()
*/
@Override
protected V provideNextVertex()
{
return queue.removeFirst();
}
/**
* Data kept for discovered vertices.
*
* @param the graph edge type
*/
protected static class SearchNodeData
{
private final E edge;
private final int depth;
/**
* Constructor
*
* @param edge edge to parent
* @param depth depth of node in search tree
*/
public SearchNodeData(E edge, int depth)
{
this.edge = edge;
this.depth = depth;
}
/**
* Edge to parent
*
* @return the edge to the parent
*/
public E getEdge()
{
return edge;
}
/**
* Depth of node in search tree
*
* @return the depth of the node in the search tree
*/
public int getDepth()
{
return depth;
}
}
}