// GraphTea Project: http://github.com/graphtheorysoftware/GraphTea // Copyright (C) 2012 Graph Theory Software Foundation: http://GraphTheorySoftware.com // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology // Distributed under the terms of the GNU Lesser General Public License (LGPL): http://www.gnu.org/licenses/ package graphtea.library; import Jama.Matrix; import graphtea.library.exceptions.InvalidEdgeException; import graphtea.library.exceptions.InvalidGraphException; import graphtea.library.exceptions.InvalidVertexException; import graphtea.library.genericcloners.EdgeVertexCopier; import graphtea.library.genericcloners.GraphConverter; import graphtea.library.util.Pair; import java.util.AbstractList; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; /** * Adjacency List Graph. * * @author Hooman Mohajeri Moghaddam, added weighted version of weightOfEdge method * @author Omid Aladini * @param <VertexType> Type of the vertices the graph can work with. * @param <EdgeType> Type of the edges the graph can work with. * <p/> * toCheck : edgeIterator class, removeEdge, removeAllEdges, copy, setDirected */ public class ListGraph<VertexType extends BaseVertex, EdgeType extends BaseEdge<VertexType>> extends BaseGraph<VertexType, EdgeType> { //The adjacency list data structure. The internal linked list of Pair<EdgeType,VertexType> //represent all edge/vertex pairs which the vertex is target of it's paired edge. private ArrayList<LinkedList<Pair<EdgeType, VertexType>>> list; //The inverse adjacency list data structure. The internal linked list of Pair<EdgeType,VertexType> //represent all edge/vertex pairs which the vertex is source of it's paired edge. private ArrayList<LinkedList<Pair<EdgeType, VertexType>>> inverseList; //list of vertices private ArrayList<VertexType> vertices; //In-degree of vertices by order stored in <code>vertices</code> object. //More clearly, the number of edges which their sources are connected to the vertex. private ArrayList<Integer> inDegree; //Out-degree of vertices by order stored in <code>vertices</code> object. //More clearly, the number of edges which their targets are connected to the vertex. private ArrayList<Integer> outDegree; //Specified whether the graph is directed. private boolean directed; //Specified whether the graph is changed since the last light iteration. private boolean guard = false; //Number of edges AKA graph order private int edgeCount = 0; /** * Constructs a graph object that stores graph data using adjacency list data structure. * * @param directed Indicated whether the graph is directed. * @param expectedNumberOfVertices Approximate number of vertices that will be * added to the graph. This paramether is optional and is available for performance * reasons. */ public ListGraph(boolean directed, int expectedNumberOfVertices) { this.directed = directed; list = new ArrayList<>(expectedNumberOfVertices); inverseList = new ArrayList<>(expectedNumberOfVertices); vertices = new ArrayList<>(expectedNumberOfVertices); outDegree = new ArrayList<>(expectedNumberOfVertices); inDegree = new ArrayList<>(expectedNumberOfVertices); } /** * Constructs an undirected graph object that stores graph data using * adjacency list data structure. */ public ListGraph() { this.directed = false; list = new ArrayList<>(); inverseList = new ArrayList<>(); vertices = new ArrayList<>(); outDegree = new ArrayList<>(); inDegree = new ArrayList<>(); } /** * Constructs a graph object that stores graph data using adjacency list data structure by importing * graph data from a pre-existing graph. A GraphConvertor object is passed as a parameter which is * reponsible for duplication/type-convertion of graph elements. * * @param <ImportVertexType> The type of vertex object which the input graph contain. * @param <ImportEdgeType> The type of edge object which the input graph contain. * @param graph The given graph * @param converter A GraphConverter object which is responsible for duplicating/converting graph * elements. * @throws InvalidGraphException Throws when the input graph is an invalid graph object. */ public <ImportVertexType extends BaseVertex, ImportEdgeType extends BaseEdge<ImportVertexType>, ImportGraphType extends BaseGraph<ImportVertexType, ImportEdgeType> > ListGraph(BaseGraph<ImportVertexType, ImportEdgeType> graph, GraphConverter<ImportVertexType, VertexType, ImportEdgeType, EdgeType, ImportGraphType, ListGraph<VertexType, EdgeType>> converter) throws InvalidGraphException { this.directed = graph.isDirected(); for (ImportVertexType v : graph) insertVertex(converter.convert(v)); Iterator<ImportEdgeType> e = graph.edgeIterator(); ImportEdgeType edge; while (e.hasNext()) { try { edge = e.next(); insertEdge(converter.convert(edge, vertices.get(graph.getId(edge.source)), vertices.get(graph.getId(edge.target)))); } catch (InvalidVertexException ex) { throw new InvalidGraphException(ex); } } } /** * A wrapper for setting vertex Id's which supports multiple vertex owners. * * @param v Vertex which the caller intends to set its Id. */ private void setId(VertexType v, int id) { if (subgraphIndex != 0) { v.setSubgraphId(subgraphIndex, id); return; } v.setId(id); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#getVerticesCount() */ @Override public int getVerticesCount() { return vertices.size(); } /** * Returns true if the <code>id</code> parameter does not indicate a vertex in this graph. * Note that vertex id's are internal marks and may change by modifying graph object. * * @param id Internal id of the vertex. * @return True if the vertex is out of range. */ private boolean vertexIdOutOfRange(int id) { return id < 0 || id >= vertices.size(); } /** * Number of times edge Iteration is called. This will set as a temporary flag into * edges in order to reduce running time of edge iteration back to O(n^2). */ private int edgeIterationIndex = 0; /** * This class iterates all, edges coming from or going to a specified vertex. * The order of edges the iterator iterate is undefined because of future code changes. * * @author Omid Aladini */ private class EdgeIterator implements Iterator<EdgeType> { private Iterator<EdgeType> edgesIterator; private EdgeType lastEdge = null; /** * Constructs an Edge Iterator object which iterates through all the edges in the graph. * Note that if the graph object is changed during iteration, the iteration may not * actually represent current state of the graph. For example, if you deleted an edge * after construction of this object, the edge would be included in the iteration. */ public EdgeIterator() { ++edgeIterationIndex; ArrayList<EdgeType> edges = new ArrayList<>(); Iterator<VertexType> it = iterator(); while (it.hasNext()) { Iterator<EdgeType> it2 = new EdgeIterator(it.next(), true); while (it2.hasNext()) { EdgeType edge = it2.next(); if (edge.edgeIterationIndex == edgeIterationIndex) continue; edge.edgeIterationIndex = edgeIterationIndex; edges.add(edge); } } edgesIterator = edges.iterator(); } /** * Constructs an Edge Iterator object which iterates through all the edges going to * or coming from the specified vertex <code>v</code>. * Note that if the graph object is changed during iteration, the iteration may not * actually represent current state of the graph. For example, if you deleted an edge * after construction of this object, the edge would be included in the iteration. * * @param v Source or target of desired edges. */ public EdgeIterator(VertexType v) throws InvalidVertexException { ++edgeIterationIndex; checkVertex(v); ArrayList<EdgeType> edges = new ArrayList<>(); Iterator<EdgeType> it = new EdgeIterator(v, true); while (it.hasNext()) edges.add(it.next()); if (directed) { it = new EdgeIterator(v, false); while (it.hasNext()) { EdgeType edge = it.next(); if (edge.edgeIterationIndex == edgeIterationIndex) continue; edge.edgeIterationIndex = edgeIterationIndex; edges.add(edge); } } edgesIterator = edges.iterator(); } /** * Constructs an Edge Iterator object which iterates through all the edges going to * or coming from (depending on the second parameter) the specified vertex <code>v</code>. * If the second parameter it true, then the first parameter is considered to be source of * all desired edges, and if it's false the first parameter is considered to be target of desired edges. * Note that if the graph object is changed during iteration, the iteration may not * actually represent current state of the graph. For example, if you deleted an edge * after construction of this object, the edge would be included in the iteration. * * @param v If the second parameter is true indicated the vertex which is source of desired edges, otherwise * it is considered to be target of desired edges. * @param source True means the first parameter should be considered source of desired edges. */ public EdgeIterator(VertexType v, boolean source) throws InvalidVertexException { checkVertex(v); ArrayList<EdgeType> edges = new ArrayList<>(); if (source) { for (Pair<EdgeType, VertexType> pev : list.get(getId(v))) edges.add(pev.first); } else { for (Pair<EdgeType, VertexType> pev : inverseList.get(getId(v))) edges.add(pev.first); } edgesIterator = edges.iterator(); } /* (non-Javadoc) * @see java.util.Iterator#hasNext() */ public boolean hasNext() { return edgesIterator.hasNext(); } /* (non-Javadoc) * @see java.util.Iterator#next() */ public EdgeType next() { lastEdge = edgesIterator.next(); return lastEdge; } /* (non-Javadoc) * @see java.util.Iterator#remove() */ public void remove() { removeEdge(lastEdge); } } /** * This is a light(weight) edge iterator which means it offers an O(1) constructor for the iterator. * This class iterates all, edges coming from or going to a specified vertex. * The order of edges the iterator iterate is undefined because of future code changes. * * @author Omid Aladini */ private class LightEdgeIterator implements Iterator<EdgeType> { //private EdgeType lastEdge = null; private EdgeType newEdge = null; int iterationType; //For iterationType 0 and 1 private Iterator<LinkedList<Pair<EdgeType, VertexType>>> lpevIterator; private Iterator<Pair<EdgeType, VertexType>> pevIterator; //For iterationType 1 private Iterator<Pair<EdgeType, VertexType>> rowIterator1, rowIterator2; //private LinkedList<Pair<EdgeType,VertexType>> row; //For iterationType 2 boolean source; /** * Constructs a light(weight) Edge Iterator object which iterates through all the edges in the graph. * The light(weight) edge iterator presents an iterator with O(1) constructor. Note that you should * not change the content of the graph during your iteration. You can still change properties of * each edge or vertex. */ public LightEdgeIterator() { iterationType = 0; lpevIterator = list.iterator(); pevIterator = null; if (!directed) ++edgeIterationIndex; guard = false; } private boolean hasNextSimpleIteration() { do { if (pevIterator == null || !pevIterator.hasNext()) { if (!lpevIterator.hasNext()) return false; LinkedList<Pair<EdgeType, VertexType>> lpev = lpevIterator.next(); pevIterator = lpev.iterator(); } while (pevIterator.hasNext()) { Pair<EdgeType, VertexType> pev = pevIterator.next(); if (directed) { newEdge = pev.first; return true; } else if (pev.first.edgeIterationIndex != edgeIterationIndex) { newEdge = pev.first; pev.first.edgeIterationIndex = edgeIterationIndex; return true; } } } while (lpevIterator.hasNext()); return false; } /** * Constructs a light(weight) Edge Iterator object which iterates through all the edges going to * or coming from the specified vertex <code>v</code>. * The light(weight) edge iterator presents an iterator with O(1) constructor. Note that you should * not change the content of the graph during your iteration. You can still change properties of * each edge or vertex. * * @param v Source or target of desired edges. */ public LightEdgeIterator(VertexType v) throws InvalidVertexException { checkVertex(v); iterationType = 1; rowIterator1 = list.get(getId(v)).iterator(); rowIterator2 = inverseList.get(getId(v)).iterator(); guard = false; } private boolean hasNextVertexIteration() { Pair<EdgeType, VertexType> pev; if (rowIterator1.hasNext()) { pev = rowIterator1.next(); newEdge = pev.first; return true; } else if (rowIterator2.hasNext() && !directed) { pev = rowIterator2.next(); newEdge = pev.first; return true; } else return false; } /** * Constructs a light(weight) Edge Iterator object which iterates through all the edges going to * or coming from (depending on the second parameter) the specified vertex <code>v</code>. * If the second parameter it true, then the first parameter is considered to be source of * all desired edges, and if it's false the first parameter is considered to be target of desired edges. * The light(weight) edge iterator presents an iterator with O(1) constructor. Note that you should * not change the content of the graph during your iteration. You can still change properties of * each edge or vertex. * * @param v If the second parameter is true indicated the vertex which is source of desired edges, otherwise * it is considered to be target of desired edges. * @param source True means the first parameter should be considered source of desired edges. */ public LightEdgeIterator(VertexType v, boolean source) throws InvalidVertexException { checkVertex(v); iterationType = 2; pevIterator = null; this.source = source; if (!directed) ++edgeIterationIndex; if (source) { rowIterator1 = list.get(getId(v)).iterator(); } else { rowIterator1 = inverseList.get(getId(v)).iterator(); } guard = false; } private boolean hasNextVertexDirectionIteration() { Pair<EdgeType, VertexType> pev; if (rowIterator1.hasNext()) { pev = rowIterator1.next(); newEdge = pev.first; return true; } else return false; } /* (non-Javadoc) * @see java.util.Iterator#hasNext() */ public boolean hasNext() { if (guard) throw new RuntimeException("Graph has changed since the initialization of this light edge iterator"); if (isHasNextCalled) return hasNextResult; isHasNextCalled = true; if (iterationType == 0) hasNextResult = hasNextSimpleIteration(); else if (iterationType == 1) hasNextResult = hasNextVertexIteration(); else //if(iterationType == 2) hasNextResult = hasNextVertexDirectionIteration(); return hasNextResult; } boolean isHasNextCalled = false; boolean hasNextResult = false; /* (non-Javadoc) * @see java.util.Iterator#next() */ public EdgeType next() { if (!isHasNextCalled) hasNext(); isHasNextCalled = false; return newEdge; } /* (non-Javadoc) * @see java.util.Iterator#remove() */ public void remove() { throw new RuntimeException("Remove is not supported for the light edge iterator."); } } /* (non-Javadoc) * @see graphtea.library.BaseGraph#edgeIterator() */ @Override public Iterator<EdgeType> edgeIterator() { return new EdgeIterator(); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#edgeIterator(null) */ @Override public Iterator<EdgeType> edgeIterator(VertexType v) throws InvalidVertexException { return new EdgeIterator(v); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#edgeIterator(null, boolean) */ @Override public Iterator<EdgeType> edgeIterator(VertexType v, boolean source) throws InvalidVertexException { return new EdgeIterator(v, source); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#lightEdgeIterator() */ @Override public Iterator<EdgeType> lightEdgeIterator() { return new LightEdgeIterator(); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#lightEdgeIterator(null) */ @Override public Iterator<EdgeType> lightEdgeIterator(VertexType v) throws InvalidVertexException { return new LightEdgeIterator(v); } /** * in a directed graph this method returns edges whose targets are v * * @param v the given vertex * @return an iterator over edges with the target v */ public Iterator<EdgeType> lightBackEdgeIterator(VertexType v) { return new LightEdgeIterator(v, false); } /** * Returns Vertex internally associated with id <code>id</code>. * * @param id Internal id of the desired vertex. * @return Vertex internally associated with id <code>id</code>. * @throws InvalidVertexException if the <code>id</code> is invalid. */ public VertexType getVertex(int id) throws InvalidVertexException { if (vertexIdOutOfRange(id)) throw new InvalidVertexException(); return vertices.get(id); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#insertEdge(null) */ @Override public void insertEdge(EdgeType newEdge) throws InvalidVertexException { int target = getId(newEdge.target); int source = getId(newEdge.source); checkVertex(newEdge.target); checkVertex(newEdge.source); guard = true; list.get(source).add(new Pair<>(newEdge, newEdge.target)); if (!directed) list.get(target).add(new Pair<>(newEdge, newEdge.source)); inverseList.get(target).add(new Pair<>(newEdge, newEdge.source)); if (!directed) inverseList.get(source).add(new Pair<>(newEdge, newEdge.target)); outDegree.set(source, outDegree.get(source) + 1); inDegree.set(target, inDegree.get(target) + 1); if (!directed) { inDegree.set(source, inDegree.get(source) + 1); outDegree.set(target, outDegree.get(target) + 1); } ++edgeCount; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#insertVertex(null) */ @Override public void insertVertex(VertexType newVertex) { if (!vertices.contains(newVertex)) { guard = true; vertices.add(newVertex); list.add(new LinkedList<>()); inverseList.add(new LinkedList<>()); setId(newVertex, vertices.size() - 1); inDegree.add(0); outDegree.add(0); } else { throw new IllegalArgumentException("Adding duplicate vertex."); } } /* (non-Javadoc) * @see java.lang.Iterable#iterator() */ @Override public Iterator<VertexType> iterator() { return vertices.iterator(); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#getAdjacencyMatrix() */ @Override public Matrix getAdjacencyMatrix() { Matrix matrix = new Matrix(getVerticesCount(), getVerticesCount()); Iterator<EdgeType> it = edgeIterator(); int targetId; int sourceId; double newValue; while (it.hasNext()) { EdgeType edge = it.next(); targetId = getId(edge.target); sourceId = getId(edge.source); newValue = matrix.get(sourceId, targetId) + 1; matrix.set(sourceId, targetId, newValue); if (!directed) matrix.set(targetId, sourceId, newValue); } return matrix; } public Matrix getWeightedAdjacencyMatrix() { Matrix matrix = new Matrix(getVerticesCount(), getVerticesCount()); Iterator<EdgeType> it = edgeIterator(); int targetId; int sourceId; double newValue; while (it.hasNext()) { EdgeType edge = it.next(); targetId = getId(edge.target); sourceId = getId(edge.source); newValue = matrix.get(sourceId, targetId) + edge.getWeight(); matrix.set(sourceId, targetId, newValue); if (!directed) matrix.set(targetId, sourceId, newValue); } return matrix; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#isDirected() */ @Override public boolean isDirected() { return directed; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#dump() */ @Override public void dump() { System.out.print('\n'); for (int i = 0; i < getVerticesCount(); i++) { int[] row = new int[getVerticesCount()]; for (Pair<EdgeType, VertexType> pev : list.get(i)) row[getId(pev.second)]++; for (int j = 0; j < getVerticesCount(); ++j) System.out.print(" " + row[j]); System.out.print('\n'); } System.out.print('\n'); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#removeAllEdges(null, null) */ @Override public void removeAllEdges(VertexType source, VertexType target) throws InvalidVertexException { Iterator<EdgeType> it = edgeIterator(source); while (it.hasNext()) { if (it.next().target == target) it.remove(); } } /* (non-Javadoc) * @see graphtea.library.BaseGraph#removeEdge(null) */ @Override public void removeEdge(EdgeType edge) throws InvalidEdgeException { checkVertex(edge.source); checkVertex(edge.target); guard = true; int sourceId = getId(edge.source); int targetId = getId(edge.target); ArrayList<LinkedList<Pair<EdgeType, VertexType>>> list = this.list; for (int i = 0; i < 2; ++i) { if (i == 1) { list = inverseList; int temp = sourceId; sourceId = targetId; targetId = temp; } Iterator<Pair<EdgeType, VertexType>> itpev = list.get(sourceId).iterator(); boolean done = false; while (itpev.hasNext()) { Pair<EdgeType, VertexType> pev = itpev.next(); if (pev.first == edge) { itpev.remove(); done = true; break; } } // if(!done) // throw new InvalidEdgeException(); if (directed) continue; itpev = list.get(targetId).iterator(); done = false; while (itpev.hasNext()) { Pair<EdgeType, VertexType> pev = itpev.next(); if (pev.first == edge) { itpev.remove(); done = true; break; } } if (!done) throw new InvalidEdgeException(); } //end 2-time for --edgeCount; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#getEdges(null, null) */ @Override public AbstractList<EdgeType> getEdges(VertexType source, VertexType target) throws InvalidVertexException { checkVertex(source); checkVertex(target); ArrayList<EdgeType> arr = new ArrayList<>(); for (Pair<EdgeType, VertexType> pev : list.get(getId(source))) { if (pev.second == target) arr.add(pev.first); } return arr; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#removeVertex(null) */ @Override public void removeVertex(VertexType v) throws InvalidVertexException { guard = true; Iterator<EdgeType> it = edgeIterator(v); while (it.hasNext()) { it.next(); it.remove(); } int vId = getId(v); list.remove(vId); inverseList.remove(vId); vertices.remove(vId); inDegree.remove(vId); outDegree.remove(vId); setVertexIds(); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#getInDegree(null) */ @Override public int getInDegree(VertexType v) throws InvalidVertexException { checkVertex(v); // return inDegree.get(getId(v)); return inverseList.get(getId(v)).size(); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#getOutDegree(null) */ @Override public int getOutDegree(VertexType v) throws InvalidVertexException { checkVertex(v); // ListIterator<Pair<EdgeType, VertexType>> iter = list.listIterator(); return list.get(getId(v)).size(); // return outDegree.get(getId(v)); //todo: outDegree seems not working properly } /** * Resets all vertices' internal Ids. */ private void setVertexIds() { try { for (int i = 0; i < getVerticesCount(); i++) setId(getVertex(i), i); } catch (InvalidVertexException e) { e.printStackTrace(); } } /* (non-Javadoc) * @see graphtea.library.BaseGraph#copy(graphtea.library.GraphConverter) */ @Override public BaseGraph<VertexType, EdgeType> copy(EdgeVertexCopier<VertexType, EdgeType> gc) throws InvalidGraphException { ListGraph<VertexType, EdgeType> oGraph = new ListGraph<>(directed, getVerticesCount()); ArrayList<VertexType> alvt = new ArrayList<>(getVerticesCount()); VertexType tempVertex; for (VertexType v : this) { tempVertex = gc.convert(v); oGraph.insertVertex(tempVertex); alvt.add(tempVertex); } Iterator<EdgeType> e = edgeIterator(); EdgeType edge; //System.out.println("Num vertix " + getVerticesCount()); while (e.hasNext()) { try { edge = e.next(); //System.out.println("An edge from " + getId(edge.source) + " to " + getId(edge.target)); oGraph.insertEdge(gc.convert(edge, alvt.get(getId(edge.source)), alvt.get(getId(edge.target)))); } catch (InvalidVertexException ex) { ex.printStackTrace(); throw new InvalidGraphException(); } } return oGraph; } public VertexType getAVertex() { if (getVerticesCount() == 0) return null; else return vertices.get(0); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#containsVertex(null) */ @Override public boolean containsVertex(VertexType v) { return vertices.contains(v); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#checkVertex(null) */ public void checkVertex(VertexType v) throws InvalidVertexException { if (vertexIdOutOfRange(getId(v))) { String message = "Out of range"; if (vertices.contains(v)) message += ":It seems that this vertex exists in two different graph objects. This is illegal."; throw new InvalidVertexException(message); } if (v != vertices.get(getId(v))) throw new InvalidVertexException("Invalid"); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#isEdges(null, null) */ @Override public boolean isEdge(VertexType source, VertexType target) throws InvalidVertexException { AbstractList<EdgeType> edges = getEdges(source, target); return (edges != null) && (edges.size() != 0); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#weightOfEdge(null, null) */ @Override public int[] weightOfEdge(VertexType source, VertexType target) throws InvalidVertexException { int[] res=null; if(isEdge(source, target)) { AbstractList<EdgeType> edges = getEdges(source, target); res=new int[edges.size()]; int i=0; for(EdgeType et : edges ) { res[i] = et.getWeight(); i++; } } return res; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#createEmptyGraph() */ @Override public ListGraph<VertexType, EdgeType> createEmptyGraph() { return new ListGraph<>(directed, 0); } /* (non-Javadoc) * @see graphtea.library.BaseGraph#setDirected(boolean) */ @Override public void setDirected(boolean directed) { if (this.directed == directed) return; guard = true; if (!directed) { Iterator<EdgeType> iet = edgeIterator(); while (iet.hasNext()) { EdgeType edge = iet.next(); list.get(getId(edge.target)).add(new Pair<>(edge, edge.source)); inverseList.get(getId(edge.source)).add(new Pair<>(edge, edge.target)); } for (int i = 0; i < getVerticesCount(); ++i) { int sum = inDegree.get(i) + outDegree.get(i); inDegree.set(i, sum); outDegree.set(i, sum); } this.directed = false; } else { Iterator<EdgeType> iet = edgeIterator(); while (iet.hasNext()) { EdgeType edge = iet.next(); Iterator<Pair<EdgeType, VertexType>> lit = list.get(getId(edge.target)).iterator(); while (lit.hasNext()) { if (lit.next().first == edge) lit.remove(); } lit = inverseList.get(getId(edge.source)).iterator(); while (lit.hasNext()) { if (lit.next().first == edge) { lit.remove(); inDegree.set(getId(edge.source), inDegree.get(getId(edge.source)) - 1); outDegree.set(getId(edge.target), outDegree.get(getId(edge.target)) - 1); } } } this.directed = true; } } /* (non-Javadoc) * @see graphtea.library.BaseGraph#getVertexArray() */ @Override public BaseVertex[] getVertexArray() { BaseVertex[] arr = new BaseVertex[getVerticesCount()]; for (VertexType v : this) arr[getId(v)] = v; return arr; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#getEdgeArray() */ @Override public int[][] getEdgeArray() { int[][] arr = new int[getVerticesCount()][]; int i = 0; int j; for (LinkedList<Pair<EdgeType, VertexType>> ll : list) { arr[i] = new int[ll.size()]; j = 0; for (Pair<EdgeType, VertexType> p : ll) { arr[i][j++] = getId(p.second); } ++i; } return arr; } /* (non-Javadoc) * @see graphtea.library.BaseGraph#clear() */ @Override public void clear() { list = new ArrayList<>(); inverseList = new ArrayList<>(); vertices = new ArrayList<>(); outDegree = new ArrayList<>(); inDegree = new ArrayList<>(); edgeIterationIndex = 0; guard = false; } @Override public int getEdgesCount() { return edgeCount; } }