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-2017, 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"; private static final String GRAPH_SPECIFICS_MUST_NOT_BE_NULL = "Graph specifics must not be null"; private boolean allowingLoops; private EdgeFactory edgeFactory; private Map edgeMap; private transient Set unmodifiableEdgeSet = null; private transient Set unmodifiableVertexSet = null; private Specifics specifics; private boolean allowingMultipleEdges; /** * 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) { Objects.requireNonNull(ef); edgeMap = new LinkedHashMap<>(); edgeFactory = ef; allowingLoops = allowLoops; allowingMultipleEdges = allowMultipleEdges; specifics = Objects.requireNonNull(createSpecifics(), GRAPH_SPECIFICS_MUST_NOT_BE_NULL); } /** * {@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; } /** * {@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, null); } /** * {@inheritDoc} */ @Override public V getEdgeTarget(E e) { return TypeUtil.uncheckedCast(getIntrusiveEdge(e).target, null); } 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; } /** * Create the specifics for this graph. Subclasses can override this method in order to adjust * the specifics and thus the space-time tradeoffs of the graph implementation. * * @return the specifics used by this graph */ protected 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 * @deprecated specifics can be changed by overriding directly {@link #createSpecifics()}. */ @Deprecated protected Specifics createUndirectedSpecifics() { return new FastLookupUndirectedSpecifics<>(this); } /** * Create directed specifics for the graph * * @return directed specifics for the graph * @deprecated specifics can be changed by overriding directly {@link #createSpecifics()}. */ @Deprecated protected Specifics createDirectedSpecifics() { return new FastLookupDirectedSpecifics<>(this); } } // End AbstractBaseGraph.java




© 2015 - 2024 Weber Informatics LLC | Privacy Policy