All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.graph.AbstractBaseGraph Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
/*
 * (C) Copyright 2003-2016, by Barak Naveh and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
package org.jgrapht.graph;

import java.io.*;
import java.util.*;

import org.jgrapht.*;
import org.jgrapht.graph.specifics.*;
import org.jgrapht.util.*;

/**
 * The most general implementation of the {@link org.jgrapht.Graph} interface. Its subclasses add
 * various restrictions to get more specific graphs. The decision whether it is directed or
 * undirected is decided at construction time and cannot be later modified (see constructor for
 * details).
 *
 * 

* This graph implementation guarantees deterministic vertex and edge set ordering (via * {@link LinkedHashMap} and {@link LinkedHashSet}). *

* * @param the graph vertex type * @param the graph edge type * * @author Barak Naveh * @since Jul 24, 2003 */ public abstract class AbstractBaseGraph extends AbstractGraph implements Graph, Cloneable, Serializable { private static final long serialVersionUID = -1263088497616142427L; private static final String LOOPS_NOT_ALLOWED = "loops not allowed"; boolean allowingLoops; private EdgeFactory edgeFactory; private EdgeSetFactory edgeSetFactory; private Map edgeMap; private transient Set unmodifiableEdgeSet = null; private transient Set unmodifiableVertexSet = null; private Specifics specifics; private boolean allowingMultipleEdges; private transient TypeUtil vertexTypeDecl = null; /** * Construct a new graph. The graph can either be directed or undirected, depending on the * specified edge factory. * * @param ef the edge factory of the new graph. * @param allowMultipleEdges whether to allow multiple edges or not. * @param allowLoops whether to allow edges that are self-loops or not. * * @throws NullPointerException if the specified edge factory is * null. */ protected AbstractBaseGraph( EdgeFactory ef, boolean allowMultipleEdges, boolean allowLoops) { if (ef == null) { throw new NullPointerException(); } edgeMap = new LinkedHashMap<>(); edgeFactory = ef; allowingLoops = allowLoops; allowingMultipleEdges = allowMultipleEdges; this.edgeSetFactory = new ArrayListFactory<>(); specifics = createSpecifics(); } /** * {@inheritDoc} */ @Override public Set getAllEdges(V sourceVertex, V targetVertex) { return specifics.getAllEdges(sourceVertex, targetVertex); } /** * Returns true if and only if self-loops are allowed in this graph. A self loop is * an edge that its source and target vertices are the same. * * @return true if and only if graph loops are allowed. */ public boolean isAllowingLoops() { return allowingLoops; } /** * Returns true if and only if multiple edges are allowed in this graph. The * meaning of multiple edges is that there can be many edges going from vertex v1 to vertex v2. * * @return true if and only if multiple edges are allowed. */ public boolean isAllowingMultipleEdges() { return allowingMultipleEdges; } /** * {@inheritDoc} */ @Override public E getEdge(V sourceVertex, V targetVertex) { return specifics.getEdge(sourceVertex, targetVertex); } /** * {@inheritDoc} */ @Override public EdgeFactory getEdgeFactory() { return edgeFactory; } /** * Set the {@link EdgeSetFactory} to use for this graph. Initially, a graph is created with a * default implementation which always supplies an {@link java.util.ArrayList} with capacity 1. * * @param edgeSetFactory factory to use for subsequently created edge sets (this call has no * effect on existing edge sets) */ public void setEdgeSetFactory(EdgeSetFactory edgeSetFactory) { this.edgeSetFactory = edgeSetFactory; } /** * Returns the {@link EdgeSetFactory} used by this graph. The default is * {@link java.util.ArrayList} with capacity 1. * * @return edgeSetFactory used by this graph */ public EdgeSetFactory getEdgeSetFactory() { return edgeSetFactory; } /** * {@inheritDoc} */ @Override public E addEdge(V sourceVertex, V targetVertex) { assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (!allowingMultipleEdges && containsEdge(sourceVertex, targetVertex)) { return null; } if (!allowingLoops && sourceVertex.equals(targetVertex)) { throw new IllegalArgumentException(LOOPS_NOT_ALLOWED); } E e = edgeFactory.createEdge(sourceVertex, targetVertex); if (containsEdge(e)) { // this restriction should stay! return null; } else { IntrusiveEdge intrusiveEdge = createIntrusiveEdge(e, sourceVertex, targetVertex); edgeMap.put(e, intrusiveEdge); specifics.addEdgeToTouchingVertices(e); return e; } } /** * {@inheritDoc} */ @Override public boolean addEdge(V sourceVertex, V targetVertex, E e) { if (e == null) { throw new NullPointerException(); } else if (containsEdge(e)) { return false; } assertVertexExist(sourceVertex); assertVertexExist(targetVertex); if (!allowingMultipleEdges && containsEdge(sourceVertex, targetVertex)) { return false; } if (!allowingLoops && sourceVertex.equals(targetVertex)) { throw new IllegalArgumentException(LOOPS_NOT_ALLOWED); } IntrusiveEdge intrusiveEdge = createIntrusiveEdge(e, sourceVertex, targetVertex); edgeMap.put(e, intrusiveEdge); specifics.addEdgeToTouchingVertices(e); return true; } private IntrusiveEdge createIntrusiveEdge(E e, V sourceVertex, V targetVertex) { IntrusiveEdge intrusiveEdge; if (e instanceof IntrusiveEdge) { intrusiveEdge = (IntrusiveEdge) e; } else { intrusiveEdge = new IntrusiveEdge(); } intrusiveEdge.source = sourceVertex; intrusiveEdge.target = targetVertex; return intrusiveEdge; } /** * {@inheritDoc} */ @Override public boolean addVertex(V v) { if (v == null) { throw new NullPointerException(); } else if (containsVertex(v)) { return false; } else { specifics.addVertex(v); return true; } } /** * {@inheritDoc} */ @Override public V getEdgeSource(E e) { return TypeUtil.uncheckedCast(getIntrusiveEdge(e).source, vertexTypeDecl); } /** * {@inheritDoc} */ @Override public V getEdgeTarget(E e) { return TypeUtil.uncheckedCast(getIntrusiveEdge(e).target, vertexTypeDecl); } private IntrusiveEdge getIntrusiveEdge(E e) { if (e instanceof IntrusiveEdge) { return (IntrusiveEdge) e; } return edgeMap.get(e); } /** * Returns a shallow copy of this graph instance. Neither edges nor vertices are cloned. * * @return a shallow copy of this set. * * @throws RuntimeException in case the clone is not supported * * @see java.lang.Object#clone() */ @Override public Object clone() { try { AbstractBaseGraph newGraph = TypeUtil.uncheckedCast(super.clone(), null); newGraph.edgeMap = new LinkedHashMap<>(); newGraph.edgeFactory = this.edgeFactory; newGraph.unmodifiableEdgeSet = null; newGraph.unmodifiableVertexSet = null; // NOTE: it's important for this to happen in an object // method so that the new inner class instance gets associated with // the right outer class instance newGraph.specifics = newGraph.createSpecifics(); Graphs.addGraph(newGraph, this); return newGraph; } catch (CloneNotSupportedException e) { e.printStackTrace(); throw new RuntimeException(); } } /** * {@inheritDoc} */ @Override public boolean containsEdge(E e) { return edgeMap.containsKey(e); } /** * {@inheritDoc} */ @Override public boolean containsVertex(V v) { return specifics.getVertexSet().contains(v); } /** * Returns the degree of the specified vertex. * * @param vertex vertex whose degree is to be calculated. * @return the degree of the specified vertex. * @see UndirectedGraph#degreeOf(Object) */ public int degreeOf(V vertex) { return specifics.degreeOf(vertex); } /** * {@inheritDoc} */ @Override public Set edgeSet() { if (unmodifiableEdgeSet == null) { unmodifiableEdgeSet = Collections.unmodifiableSet(edgeMap.keySet()); } return unmodifiableEdgeSet; } /** * {@inheritDoc} */ @Override public Set edgesOf(V vertex) { assertVertexExist(vertex); return specifics.edgesOf(vertex); } /** * Returns the "in degree" of the specified vertex. * * @param vertex vertex whose in degree is to be calculated. * @return the in degree of the specified vertex. * * @see DirectedGraph#inDegreeOf(Object) */ public int inDegreeOf(V vertex) { assertVertexExist(vertex); return specifics.inDegreeOf(vertex); } /** * Returns a set of all edges incoming into the specified vertex. * * @param vertex the vertex for which the list of incoming edges to be returned * @return a set of all edges incoming into the specified vertex * @see DirectedGraph#incomingEdgesOf(Object) */ public Set incomingEdgesOf(V vertex) { assertVertexExist(vertex); return specifics.incomingEdgesOf(vertex); } /** * Returns the "out degree" of the specified vertex. * * @param vertex vertex whose out degree is to be calculated * @return the out degree of the specified vertex * @see DirectedGraph#outDegreeOf(Object) */ public int outDegreeOf(V vertex) { assertVertexExist(vertex); return specifics.outDegreeOf(vertex); } /** * Returns a set of all edges outgoing from the specified vertex. * * @param vertex the vertex for which the list of outgoing edges to be returned * @return a set of all edges outgoing from the specified vertex * @see DirectedGraph#outgoingEdgesOf(Object) */ public Set outgoingEdgesOf(V vertex) { assertVertexExist(vertex); return specifics.outgoingEdgesOf(vertex); } /** * {@inheritDoc} */ @Override public E removeEdge(V sourceVertex, V targetVertex) { E e = getEdge(sourceVertex, targetVertex); if (e != null) { specifics.removeEdgeFromTouchingVertices(e); edgeMap.remove(e); } return e; } /** * {@inheritDoc} */ @Override public boolean removeEdge(E e) { if (containsEdge(e)) { specifics.removeEdgeFromTouchingVertices(e); edgeMap.remove(e); return true; } else { return false; } } /** * {@inheritDoc} */ @Override public boolean removeVertex(V v) { if (containsVertex(v)) { Set touchingEdgesList = edgesOf(v); // cannot iterate over list - will cause // ConcurrentModificationException removeAllEdges(new ArrayList<>(touchingEdgesList)); specifics.getVertexSet().remove(v); // remove the vertex itself return true; } else { return false; } } /** * {@inheritDoc} */ @Override public Set vertexSet() { if (unmodifiableVertexSet == null) { unmodifiableVertexSet = Collections.unmodifiableSet(specifics.getVertexSet()); } return unmodifiableVertexSet; } /** * {@inheritDoc} */ @Override public double getEdgeWeight(E e) { if (e instanceof DefaultWeightedEdge) { return ((DefaultWeightedEdge) e).getWeight(); } else if (e == null) { throw new NullPointerException(); } else { return WeightedGraph.DEFAULT_EDGE_WEIGHT; } } /** * Assigns a weight to an edge. * * @param e edge on which to set weight * @param weight new weight for edge * @see WeightedGraph#setEdgeWeight(Object, double) */ public void setEdgeWeight(E e, double weight) { assert (e instanceof DefaultWeightedEdge) : e.getClass(); ((DefaultWeightedEdge) e).weight = weight; } private Specifics createSpecifics() { if (this instanceof DirectedGraph) { return createDirectedSpecifics(); } else if (this instanceof UndirectedGraph) { return createUndirectedSpecifics(); } else { throw new IllegalArgumentException( "must be instance of either DirectedGraph or UndirectedGraph"); } } /** * Create undirected specifics for the graph * * @return undirected specifics for the graph */ protected Specifics createUndirectedSpecifics() { return new FastLookupUndirectedSpecifics<>(this); } /** * Create directed specifics for the graph * * @return directed specifics for the graph */ protected Specifics createDirectedSpecifics() { return new FastLookupDirectedSpecifics<>(this); } private static class ArrayListFactory implements EdgeSetFactory, Serializable { private static final long serialVersionUID = 5936902837403445985L; /** * {@inheritDoc} */ @Override public Set createEdgeSet(VV vertex) { // NOTE: use size 1 to keep memory usage under control // for the common case of vertices with low degree return new ArrayUnenforcedSet<>(1); } } } // End AbstractBaseGraph.java




© 2015 - 2025 Weber Informatics LLC | Privacy Policy