org.jgrapht.alg.DirectedNeighborIndex Maven / Gradle / Ivy
Go to download
JGraphT is a free Java graph library
that provides mathematical graph-theory objects and algorithms
The newest version!
/* ==========================================
* JGraphT : a free Java graph-theory library
* ==========================================
*
* Project Info: http://jgrapht.sourceforge.net/
* Project Creator: Barak Naveh (http://sourceforge.net/users/barak_naveh)
*
* (C) Copyright 2003-2007, by Barak Naveh and Contributors.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation,
* Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
/* --------------------------
* DirectedNeighborIndex.java
* --------------------------
* (C) Copyright 2005-2007, by Charles Fry and Contributors.
*
* Original Author: Charles Fry
*
* $Id: DirectedNeighborIndex.java 568 2007-09-30 00:12:18Z perfecthash $
*
* Changes
* -------
* 13-Dec-2005 : Initial revision (CF);
*
*/
package org.jgrapht.alg;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.alg.NeighborIndex.*;
import org.jgrapht.event.*;
/**
* Maintains a cache of each vertex's neighbors. While lists of neighbors can be
* obtained from {@link Graphs}, they are re-calculated at each invocation by
* walking a vertex's incident edges, which becomes inordinately expensive when
* performed often.
*
* A vertex's neighbors are cached the first time they are asked for (i.e.
* the index is built on demand). The index will only be updated automatically
* if it is added to the associated graph as a listener. If it is added as a
* listener to a graph other than the one it indexes, results are undefined.
*
* @author Charles Fry
* @since Dec 13, 2005
*/
public class DirectedNeighborIndex
implements GraphListener
{
//~ Instance fields --------------------------------------------------------
Map> predecessorMap = new HashMap>();
Map> successorMap = new HashMap>();
private DirectedGraph graph;
//~ Constructors -----------------------------------------------------------
/**
* Creates a neighbor index for the specified directed graph.
*
* @param g the graph for which a neighbor index is to be created.
*/
public DirectedNeighborIndex(DirectedGraph g)
{
graph = g;
}
//~ Methods ----------------------------------------------------------------
/**
* Returns the set of vertices which are the predecessors of a specified
* vertex. The returned set is backed by the index, and will be updated when
* the graph changes as long as the index has been added as a listener to
* the graph.
*
* @param v the vertex whose predecessors are desired
*
* @return all unique predecessors of the specified vertex
*/
public Set predecessorsOf(V v)
{
return getPredecessors(v).getNeighbors();
}
/**
* Returns the set of vertices which are the predecessors of a specified
* vertex. If the graph is a multigraph, vertices may appear more than once
* in the returned list. Because a list of predecessors can not be
* efficiently maintained, it is reconstructed on every invocation by
* duplicating entries in the neighbor set. It is thus more efficient to use
* {@link #predecessorsOf(Object)} unless duplicate neighbors are required.
*
* @param v the vertex whose predecessors are desired
*
* @return all predecessors of the specified vertex
*/
public List predecessorListOf(V v)
{
return getPredecessors(v).getNeighborList();
}
/**
* Returns the set of vertices which are the successors of a specified
* vertex. The returned set is backed by the index, and will be updated when
* the graph changes as long as the index has been added as a listener to
* the graph.
*
* @param v the vertex whose successors are desired
*
* @return all unique successors of the specified vertex
*/
public Set successorsOf(V v)
{
return getSuccessors(v).getNeighbors();
}
/**
* Returns the set of vertices which are the successors of a specified
* vertex. If the graph is a multigraph, vertices may appear more than once
* in the returned list. Because a list of successors can not be efficiently
* maintained, it is reconstructed on every invocation by duplicating
* entries in the neighbor set. It is thus more effecient to use {@link
* #successorsOf(Object)} unless dupliate neighbors are required.
*
* @param v the vertex whose successors are desired
*
* @return all successors of the specified vertex
*/
public List successorListOf(V v)
{
return getSuccessors(v).getNeighborList();
}
/**
* @see GraphListener#edgeAdded(GraphEdgeChangeEvent)
*/
public void edgeAdded(GraphEdgeChangeEvent e)
{
E edge = e.getEdge();
V source = graph.getEdgeSource(edge);
V target = graph.getEdgeTarget(edge);
// if a map does not already contain an entry,
// then skip addNeighbor, since instantiating the map
// will take care of processing the edge (which has already
// been added)
if (successorMap.containsKey(source)) {
getSuccessors(source).addNeighbor(target);
} else {
getSuccessors(source);
}
if (predecessorMap.containsKey(target)) {
getPredecessors(target).addNeighbor(source);
} else {
getPredecessors(target);
}
}
/**
* @see GraphListener#edgeRemoved(GraphEdgeChangeEvent)
*/
public void edgeRemoved(GraphEdgeChangeEvent e)
{
E edge = e.getEdge();
V source = graph.getEdgeSource(edge);
V target = graph.getEdgeTarget(edge);
if (successorMap.containsKey(source)) {
successorMap.get(source).removeNeighbor(target);
}
if (predecessorMap.containsKey(target)) {
predecessorMap.get(target).removeNeighbor(source);
}
}
/**
* @see VertexSetListener#vertexAdded(GraphVertexChangeEvent)
*/
public void vertexAdded(GraphVertexChangeEvent e)
{
// nothing to cache until there are edges
}
/**
* @see VertexSetListener#vertexRemoved(GraphVertexChangeEvent)
*/
public void vertexRemoved(GraphVertexChangeEvent e)
{
predecessorMap.remove(e.getVertex());
successorMap.remove(e.getVertex());
}
private Neighbors getPredecessors(V v)
{
Neighbors neighbors = predecessorMap.get(v);
if (neighbors == null) {
neighbors =
new Neighbors(v,
Graphs.predecessorListOf(graph, v));
predecessorMap.put(v, neighbors);
}
return neighbors;
}
private Neighbors getSuccessors(V v)
{
Neighbors neighbors = successorMap.get(v);
if (neighbors == null) {
neighbors =
new Neighbors(v,
Graphs.successorListOf(graph, v));
successorMap.put(v, neighbors);
}
return neighbors;
}
}
// End DirectedNeighborIndex.java