Updating graph
* Implemented MatrixGraph * Changed save/load logics (test not passing)
This commit is contained in:
15
build.gradle
15
build.gradle
@@ -14,13 +14,9 @@ test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs "src"
|
||||
srcDirs "test"
|
||||
}
|
||||
}
|
||||
sourceSets.main.java {
|
||||
srcDirs "src"
|
||||
srcDirs "test"
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -28,8 +24,9 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
|
||||
implementation 'org.junit.jupiter:junit-jupiter:5.5.2'
|
||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
|
||||
|
||||
/*compile group: 'commons-collections', name: 'commons-collections', version: '3.2'*/
|
||||
testCompile 'junit:junit:4.4'
|
||||
testCompile 'junit:junit:5.5.2'
|
||||
}
|
||||
@@ -1,21 +1,13 @@
|
||||
package berack96.lib.graph;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import berack96.lib.graph.models.GraphSaveStructure;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
/**
|
||||
* An interface for the graphs.<br>
|
||||
* This interface is used for the graphs with Directed edges.<br>
|
||||
@@ -27,11 +19,10 @@ import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
*/
|
||||
public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
|
||||
final String NOT_DAG = "The graph is not a DAG";
|
||||
final String NOT_CONNECTED = "The source vertex doesn't have a path that reach the destination";
|
||||
final String PARAM_NULL = "The parameter must not be null";
|
||||
final String VERTEX_NOT_CONTAINED = "The vertex must be contained in the graph";
|
||||
final Gson GSON = new Gson();
|
||||
String NOT_DAG = "The graph is not a DAG";
|
||||
String NOT_CONNECTED = "The source vertex doesn't have a path that reach the destination";
|
||||
String PARAM_NULL = "The parameter must not be null";
|
||||
String VERTEX_NOT_CONTAINED = "The vertex must be contained in the graph";
|
||||
|
||||
/**
|
||||
* Tells if the graph has some cycle.<br>
|
||||
@@ -70,16 +61,16 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
Vertex<V> get(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Add the vertex to the graph. If it's already in the graph it will be replaced.<br>
|
||||
* Add the vertex to the graph. If it's already in the graph it will be replaced and all its edges will be resetted.<br>
|
||||
* Of course the vertex added will have no edge to any other vertex nor form any other vertex.
|
||||
*
|
||||
* @param vertex the vertex to add
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
void addVertex(V vertex) throws NullPointerException;
|
||||
void add(V vertex) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Add the specified vertex to the graph only if the graph doesn't contains it.<br>
|
||||
@@ -89,7 +80,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
* @return true if the vertex is added, false if the graph contains the vertex and therefore the new one is not added
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
boolean addVertexIfAbsent(V vertex) throws NullPointerException;
|
||||
boolean addIfAbsent(V vertex) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Add all the vertices contained in the collection to the graph.<br>
|
||||
@@ -99,7 +90,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
* @param vertices a collection of the vertices to add
|
||||
* @throws NullPointerException if the set is null
|
||||
*/
|
||||
void addAllVertices(Collection<V> vertices) throws NullPointerException;
|
||||
void addAll(Collection<V> vertices) throws NullPointerException;
|
||||
|
||||
/**
|
||||
* Remove the selected vertex from the graph.<br>
|
||||
@@ -109,13 +100,13 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained
|
||||
*/
|
||||
void removeVertex(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
void remove(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove all the vertex contained in the graph.<br>
|
||||
* After this method's call the graph will be empty; no vertices nor edges.
|
||||
*/
|
||||
void removeAllVertex();
|
||||
void removeAll();
|
||||
|
||||
/**
|
||||
* Get all the marks of this graph.<br>
|
||||
@@ -408,11 +399,11 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained in the graph
|
||||
*/
|
||||
Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
Collection<V> getChildrens(V vertex) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Get all the vertices that have the vertex passed as their child.<br>
|
||||
* Basically is the opposite of {@link #getChildren(Object)}<br>
|
||||
* Basically is the opposite of {@link #getChildrens(Object)}<br>
|
||||
* Note: depending on the implementation, modifying the returned collection<br>
|
||||
* could affect the graph behavior and the changes could be reflected to the graph.
|
||||
*
|
||||
@@ -462,7 +453,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
*
|
||||
* @return the number of vertices
|
||||
*/
|
||||
int numberOfVertices();
|
||||
int size();
|
||||
|
||||
/**
|
||||
* Tells how many edges are in the graph.
|
||||
@@ -500,7 +491,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
* A topological ordering of a graph is a linear ordering of its vertices such that for
|
||||
* every directed edge (V1, V2) from vertex V1 to vertex V2, V2 comes before V1 in the ordering.
|
||||
*
|
||||
* @return an array containing the topological order of the vertices
|
||||
* @return a list containing the topological order of the vertices
|
||||
* @throws UnsupportedOperationException if the graph is not a DAG (see {@link #isDAG()})
|
||||
*/
|
||||
List<V> topologicalSort() throws UnsupportedOperationException;
|
||||
@@ -521,7 +512,7 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
* Of course the sub-graph will contain the edges that link the vertices, but only the one selected.
|
||||
*
|
||||
* @param source the source vertex
|
||||
* @param depth the maximum depth (must be a positive number, if >=0 a graph containing only the source is returned)
|
||||
* @param depth the maximum depth (must be a positive number, if <=0 a graph containing only the source is returned)
|
||||
* @return a sub-graph of the original
|
||||
* @throws NullPointerException if the vertex is null
|
||||
* @throws IllegalArgumentException if the vertex is not contained
|
||||
@@ -562,91 +553,5 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
|
||||
*/
|
||||
Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Save the Graph passed as input to a file inserted as parameter.<br>
|
||||
* The resulting file is a Json string representing all the graph.<br>
|
||||
* If the directory for getting through the file do not exist,<br>
|
||||
* then it is created.<br>
|
||||
* For now the marks are not included.
|
||||
*
|
||||
* @param graph the graph to save
|
||||
* @param file the name of the file
|
||||
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
|
||||
*/
|
||||
static void save(Graph<?, ?> graph, String file) throws IOException {
|
||||
save(graph, "", file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the Graph passed as input to a file inserted as parameter.<br>
|
||||
* The resulting file is a Json string representing all the graph.<br>
|
||||
* If the directory for getting through the file do not exist,<br>
|
||||
* then it is created.<br>
|
||||
* For now the marks are not included.<br>
|
||||
* The additional parameter is used if you want to save other as well as the graph.
|
||||
*
|
||||
* @param graph the graph to save
|
||||
* @param other other things to save
|
||||
* @param file the name of the file
|
||||
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
|
||||
*/
|
||||
static void save(Graph<?, ?> graph, String other, String file) throws IOException {
|
||||
GraphSaveStructure save = new GraphSaveStructure(graph, other);
|
||||
int slash = file.lastIndexOf("\\");
|
||||
if(slash == -1)
|
||||
slash = file.lastIndexOf("/");
|
||||
if(slash != -1) {
|
||||
String dir = file.substring(0, slash);
|
||||
File fDir = new File(dir);
|
||||
fDir.mkdirs();
|
||||
}
|
||||
|
||||
FileWriter writer = new FileWriter(file);
|
||||
|
||||
GSON.toJson(save, writer);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an already saved graph in an instance of a graph.
|
||||
* Before loading the graph, it is emptied.
|
||||
*
|
||||
* @param <V> the parameter needed for the vertex
|
||||
* @param <W> the parameter needed for the weight
|
||||
* @param graph the graph to load with
|
||||
* @param file the file where the graph is saved
|
||||
* @param classV the class used for the Vertex
|
||||
* @param classW the class used for the Weight
|
||||
* @return the string saved in other, if any
|
||||
* @throws IOException for any possible reason, the most common: the file doesn't exist
|
||||
* @throws NullPointerException if the graph is null
|
||||
* @throws JsonSyntaxException if the file is malformed or corrupted
|
||||
*/
|
||||
static <V, W extends Number> String load(Graph<V, W> graph, String file, Class<V> classV, Class<W> classW) throws IOException, NullPointerException, JsonSyntaxException {
|
||||
FileReader reader = new FileReader(file);
|
||||
StringBuilder fileContent = new StringBuilder();
|
||||
int c;
|
||||
|
||||
while((c = reader.read()) != -1)
|
||||
fileContent.append((char)c);
|
||||
reader.close();
|
||||
GraphSaveStructure save = GSON.fromJson(fileContent.toString(), GraphSaveStructure.class);
|
||||
|
||||
graph.removeAllVertex();
|
||||
for(String str : save.vertices)
|
||||
graph.addVertex(GSON.fromJson(str, classV));
|
||||
|
||||
for(int i = 0; i<save.edges.length; i++)
|
||||
graph.addEdge(
|
||||
GSON.fromJson(save.edges[i].src, classV),
|
||||
GSON.fromJson(save.edges[i].dest, classV),
|
||||
GSON.fromJson(save.edges[i].weight, classW));
|
||||
/*
|
||||
for(int i = 0; i<save.marks.length; i++)
|
||||
graph.mark(GSON.fromJson(save.marks[i].vert, classV), save.marks[i].mark);
|
||||
*/
|
||||
return save.other;
|
||||
}
|
||||
|
||||
// TODO maybe, but i don't think so... STATIC DISTANCE V* -> V*
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package berack96.lib.graph;
|
||||
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
/**
|
||||
* Class used for represent a vertex of the graph.<br>
|
||||
* The vertex contained is linked with the graph, so if any changes are made to
|
||||
@@ -105,7 +105,7 @@ public class Vertex<V> {
|
||||
*/
|
||||
public Collection<V> getChildren() throws UnsupportedOperationException {
|
||||
throwIfNotContained();
|
||||
return graph.getChildren(vertex);
|
||||
return graph.getChildrens(vertex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,7 +219,7 @@ public class Vertex<V> {
|
||||
* Add the vertex to the graph only if it's not already in the graph.
|
||||
*/
|
||||
public void addIfAbsent() {
|
||||
graph.addVertexIfAbsent(vertex);
|
||||
graph.addIfAbsent(vertex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +228,7 @@ public class Vertex<V> {
|
||||
*/
|
||||
public void remove() {
|
||||
if (graph.contains(vertex))
|
||||
graph.removeVertex(vertex);
|
||||
graph.remove(vertex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -240,7 +240,7 @@ public class Vertex<V> {
|
||||
* @throws NullPointerException if the strategy is null
|
||||
* @throws UnsupportedOperationException if the vertex is not in the graph anymore
|
||||
*/
|
||||
public VisitInfo<V> visit(final VisitStrategy strategy, final Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
|
||||
public VisitInfo<V> visit(final VisitStrategy<V, ?> strategy, final Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
|
||||
throwIfNotContained();
|
||||
return graph.visit(vertex, (VisitStrategy<V, Number>) strategy, visit);
|
||||
}
|
||||
|
||||
579
src/berack96/lib/graph/impl/AGraph.java
Normal file
579
src/berack96/lib/graph/impl/AGraph.java
Normal file
@@ -0,0 +1,579 @@
|
||||
package berack96.lib.graph.impl;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.Vertex;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.Depth;
|
||||
import berack96.lib.graph.visit.impl.Dijkstra;
|
||||
import berack96.lib.graph.visit.impl.Tarjan;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* An abstract class used for a basic implementation of a graph.<br>
|
||||
* It implements the visits, the markers and some other stupid to implement methods.<br>
|
||||
* It might not be super efficient but it works and you can always overwrite its methods for better performance
|
||||
*
|
||||
* @param <V> the vertex
|
||||
* @param <W> the weight
|
||||
* @author Berack96
|
||||
*/
|
||||
public abstract class AGraph<V, W extends Number> implements Graph<V, W> {
|
||||
|
||||
/**
|
||||
* Map that contains the marker as key and a set of all the vertices that has it as the value.<br>
|
||||
* This map is build like this for performance in creating the marker for multiple vertices.<br>
|
||||
* If you flip the parameters (object and set) then has more performance over the single vertex.
|
||||
*/
|
||||
private final Map<Object, Set<V>> markers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Need this variable for not calculating each time the SCC or the cyclic part if the graph doesn't change
|
||||
*/
|
||||
private Tarjan<V, W> tarjan = null;
|
||||
|
||||
/**
|
||||
* Need this variable for not calculating each time the distance from a vertex to all his destinations if the graph doesn't change
|
||||
*/
|
||||
final private Map<V, Dijkstra<V, W>> dijkstra = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Get a new instance of this Graph.
|
||||
*
|
||||
* @return A new instance of the graph
|
||||
*/
|
||||
protected abstract Graph<V, W> getNewInstance();
|
||||
|
||||
/**
|
||||
* Add a vertex to the graph
|
||||
*
|
||||
* @param vertex the vertex to add
|
||||
*/
|
||||
protected abstract void addVertex(V vertex);
|
||||
|
||||
/**
|
||||
* Check if a vertex is in the graph
|
||||
*
|
||||
* @param vertex the vertex to check
|
||||
* @return true if is contained, false otherwise
|
||||
*/
|
||||
protected abstract boolean containsVertex(V vertex);
|
||||
|
||||
/**
|
||||
* Remove a vertex from the graph
|
||||
*
|
||||
* @param vertex the vertex to remove
|
||||
*/
|
||||
protected abstract void removeVertex(V vertex);
|
||||
|
||||
/**
|
||||
* Remove all vertices from the graph
|
||||
*/
|
||||
protected abstract void removeAllVertices();
|
||||
|
||||
/**
|
||||
* Check if the edge is in the graph
|
||||
* @param vertex1 the source vertex
|
||||
* @param vertex2 the destination vertex
|
||||
* @return true if the edge is in the graph, false otherwise
|
||||
*/
|
||||
protected abstract boolean containsEdgeImpl(V vertex1, V vertex2);
|
||||
|
||||
/**
|
||||
* Add a new edge to the graph.<br>
|
||||
* If the edge already exist then replace the weight and returns the old one.
|
||||
*
|
||||
* @param vertex1 the source vertex
|
||||
* @param vertex2 the destination vertex
|
||||
* @param weight the weight of the new edge
|
||||
* @return the old weight, null otherwise
|
||||
*/
|
||||
protected abstract W addEdgeImpl(V vertex1, V vertex2, W weight);
|
||||
|
||||
/**
|
||||
* Get the weight of the edge
|
||||
*
|
||||
* @param vertex1 the source vertex
|
||||
* @param vertex2 the destination vertex
|
||||
* @return the weight of the edge
|
||||
*/
|
||||
protected abstract W getWeightImpl(V vertex1, V vertex2);
|
||||
|
||||
/**
|
||||
* Retrieves all the edges that goes out of a vertex.<br>
|
||||
* (where the vertex is the source)
|
||||
*
|
||||
* @param vertex the source vertex
|
||||
* @return a collection of edges
|
||||
*/
|
||||
protected abstract Collection<Edge<V, W>> getEdgesOutImpl(V vertex);
|
||||
|
||||
/**
|
||||
* Retrieves all the edges that goes in of a vertex.<br>
|
||||
* (where the vertex is the destination)
|
||||
*
|
||||
* @param vertex the destination vertex
|
||||
* @return a collection of edges
|
||||
*/
|
||||
protected abstract Collection<Edge<V, W>> getEdgesInImpl(V vertex);
|
||||
|
||||
/**
|
||||
* Remove the edge from the graph
|
||||
* @param vertex1 the source vertex
|
||||
* @param vertex2 the destination vertex
|
||||
*/
|
||||
protected abstract void removeEdgeImpl(V vertex1, V vertex2);
|
||||
|
||||
/**
|
||||
* Removes all the edges that goes out of a vertex.<br>
|
||||
* (where the vertex is the source)
|
||||
* @param vertex the source vertex
|
||||
*/
|
||||
protected abstract void removeAllOutEdgeImpl(V vertex);
|
||||
|
||||
/**
|
||||
* Removes all the edges that goes in of a vertex.<br>
|
||||
* (where the vertex is the destination)
|
||||
*
|
||||
* @param vertex the destination vertex
|
||||
*/
|
||||
protected abstract void removeAllInEdgeImpl(V vertex);
|
||||
|
||||
@Override
|
||||
public boolean isCyclic() {
|
||||
return stronglyConnectedComponents().size() != size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDAG() {
|
||||
return !isCyclic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<V> get(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
return new Vertex<>(this, vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(V vertex) throws NullPointerException {
|
||||
checkNull(vertex);
|
||||
return containsVertex(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(V vertex) throws NullPointerException {
|
||||
checkNull(vertex);
|
||||
if(containsVertex(vertex))
|
||||
remove(vertex);
|
||||
addVertex(vertex);
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addIfAbsent(V vertex) throws NullPointerException {
|
||||
if(contains(vertex))
|
||||
return false;
|
||||
add(vertex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAll(Collection<V> vertices) throws NullPointerException {
|
||||
checkNull(vertices);
|
||||
vertices.forEach(this::addIfAbsent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
unMark(vertex);
|
||||
removeVertex(vertex);
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() {
|
||||
unMarkAll();
|
||||
removeAllVertices();
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
|
||||
checkNull(vertex1);
|
||||
checkNull(vertex2);
|
||||
return containsEdgeImpl(vertex1, vertex2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex1);
|
||||
checkNullAndExist(vertex2);
|
||||
graphChanged();
|
||||
return addEdgeImpl(vertex1, vertex2, weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
checkNull(edge);
|
||||
return addEdge(edge.getSource(), edge.getDestination(), edge.getWeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
|
||||
addIfAbsent(vertex1);
|
||||
addIfAbsent(vertex2);
|
||||
return addEdge(vertex1, vertex2, weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
return addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
|
||||
edges.forEach((edge) -> addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex1);
|
||||
checkNullAndExist(vertex2);
|
||||
return getWeightImpl(vertex1, vertex2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
return getEdgesOutImpl(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
return getEdgesInImpl(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex1);
|
||||
checkNullAndExist(vertex2);
|
||||
removeEdgeImpl(vertex1, vertex2);
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
removeAllOutEdgeImpl(vertex);
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
removeAllInEdgeImpl(vertex);
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
removeVertex(vertex);
|
||||
addVertex(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge() {
|
||||
Collection<V> vert = vertices();
|
||||
removeAllVertices();
|
||||
addAll(vert);
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> vertices() {
|
||||
Set<V> set = new HashSet<>();
|
||||
this.forEach(set::add);
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edges() {
|
||||
Set<Edge<V,W>> set = new HashSet<>();
|
||||
this.forEach( v -> set.addAll(this.getEdgesOut(v)));
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return vertices().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfEdges() {
|
||||
return edges().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
return degreeIn(vertex) + degreeOut(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
return getAncestors(vertex).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
return getChildrens(vertex).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> marks() {
|
||||
Collection<Object> ret = new HashSet<>();
|
||||
markers.forEach((m, v) -> {
|
||||
if(v.size() > 0)
|
||||
ret.add(m);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
checkNull(mark);
|
||||
|
||||
Set<V> set = markers.computeIfAbsent(mark, (v) -> new HashSet<>());
|
||||
set.add(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
checkNull(mark);
|
||||
markers.get(mark).remove(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
markers.forEach( (mark, set) -> set.remove(vertex) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
|
||||
checkNull(mark);
|
||||
return markers.computeIfAbsent(mark, (v) -> new HashSet<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
Collection<Object> marks = new HashSet<>();
|
||||
markers.forEach( (mark, set) -> {
|
||||
if (set.contains(vertex))
|
||||
marks.add(mark);
|
||||
});
|
||||
|
||||
return marks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll(Object mark) {
|
||||
checkNull(mark);
|
||||
markers.remove(mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll() {
|
||||
markers.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
Collection<Edge<V,W>> coll = getEdgesIn(vertex);
|
||||
coll.addAll(getEdgesOut(vertex));
|
||||
return coll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getChildrens(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
Set<V> set = new HashSet<>();
|
||||
getEdgesOut(vertex).forEach(e -> set.add(e.getDestination()));
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
Set<V> set = new HashSet<>();
|
||||
getEdgesIn(vertex).forEach(e -> set.add(e.getSource()));
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
|
||||
return strategy.visit(this, source, visit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> transpose() {
|
||||
Graph<V, W> graph = getNewInstance();
|
||||
graph.addAll(vertices());
|
||||
for(Edge<V, W> edge : edges())
|
||||
graph.addEdge(edge.getDestination(), edge.getSource(), edge.getWeight());
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> topologicalSort() throws UnsupportedOperationException {
|
||||
if (!isDAG())
|
||||
throw new UnsupportedOperationException(NOT_DAG);
|
||||
return getTarjan().getTopologicalSort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Collection<V>> stronglyConnectedComponents() {
|
||||
return getTarjan().getSCC();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
|
||||
Graph<V, W> sub = getNewInstance();
|
||||
|
||||
Set<V> vertices = new HashSet<>();
|
||||
new Depth<V, W>(Math.max(depth, 0)).visit(this, source, vertices::add);
|
||||
|
||||
sub.addAll(vertices);
|
||||
for (V vertex : vertices)
|
||||
getEdgesOut(vertex).forEach((edge) -> {
|
||||
if(sub.contains(edge.getSource()) && sub.contains(edge.getDestination()))
|
||||
sub.addEdge(edge);
|
||||
});
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(final Object...marker) {
|
||||
final Graph<V, W> sub = getNewInstance();
|
||||
final Set<V> allVertices = new HashSet<>();
|
||||
final Set<Object> allMarkers = new HashSet<>();
|
||||
final boolean isEmpty = (marker == null || marker.length == 0);
|
||||
|
||||
if (!isEmpty)
|
||||
Collections.addAll(allMarkers, marker);
|
||||
|
||||
markers.forEach( (mark, set) -> {
|
||||
if (isEmpty || allMarkers.contains(mark))
|
||||
allVertices.addAll(set);
|
||||
});
|
||||
|
||||
if (isEmpty) {
|
||||
Collection<V> toAdd = vertices();
|
||||
toAdd.removeAll(allVertices);
|
||||
allVertices.clear();
|
||||
allVertices.addAll(toAdd);
|
||||
}
|
||||
|
||||
sub.addAll(allVertices);
|
||||
for (V vertex : sub.vertices())
|
||||
this.edgesOf(vertex).forEach( (edge) -> {
|
||||
if(sub.contains(edge.getSource()) && sub.contains(edge.getDestination()))
|
||||
sub.addEdge(edge);
|
||||
});
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Edge<V, W>> distance(V source, V destination) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
|
||||
checkNullAndExist(source);
|
||||
checkNullAndExist(destination);
|
||||
|
||||
Dijkstra<V, W> dijkstra = getDijkstra(source); /* Cached */
|
||||
List<Edge<V, W>> path = dijkstra.getLastDistance().get(destination);
|
||||
if (path == null)
|
||||
throw new UnsupportedOperationException(NOT_CONNECTED);
|
||||
return new ArrayList<>(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(source);
|
||||
return new HashMap<>(getDijkstra(source).getLastDistance()); /* Cached */
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple function that reset all the caching variables if the graph changed
|
||||
*/
|
||||
private void graphChanged() {
|
||||
tarjan = null;
|
||||
dijkstra.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the object passed is null.
|
||||
* If it is throw an exception.
|
||||
* @param object the object to test
|
||||
*/
|
||||
private void checkNull(Object object) {
|
||||
if (object == null)
|
||||
throw new NullPointerException(PARAM_NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the vertex passed is null and if exist in the graph.
|
||||
* If not then throws eventual exception
|
||||
* @param vertex the vertex to test
|
||||
*/
|
||||
private void checkNullAndExist(V vertex) {
|
||||
checkNull(vertex);
|
||||
if (!contains(vertex))
|
||||
throw new IllegalArgumentException(VERTEX_NOT_CONTAINED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple function that return the result of the Dijkstra visit, with the starting point as source.<br>
|
||||
* It also cache it, so multiple call will return always the same value unless the graph has changed.
|
||||
* @param source the source of the visit
|
||||
* @return the complete visit
|
||||
*/
|
||||
private Dijkstra<V, W> getDijkstra(V source) {
|
||||
if (dijkstra.get(source) == null) {
|
||||
Dijkstra<V, W> newDijkstra = new Dijkstra<>();
|
||||
newDijkstra.visit(this, source, null);
|
||||
dijkstra.put(source, newDijkstra);
|
||||
}
|
||||
|
||||
return dijkstra.get(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple function that return the result of the Tarjan visit.<br>
|
||||
* It also cache it, so multiple call will return always the same value unless the graph has changed.
|
||||
* @return the tarjan visit
|
||||
*/
|
||||
private Tarjan<V, W> getTarjan() {
|
||||
if (tarjan == null) {
|
||||
tarjan = new Tarjan<>();
|
||||
tarjan.visit(this, null, null);
|
||||
}
|
||||
|
||||
return tarjan;
|
||||
}
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
package berack96.lib.graph.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.Vertex;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
public class AdjGraph<V, W extends Number> implements Graph<V, W> {
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCyclic() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDAG() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addVertex(V vertex) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addVertexIfAbsent(V vertex) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllVertices(Collection<V> vertices) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVertex(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllVertex() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(V vertex) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> marks() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll(Object mark) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> vertices() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edges() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfVertices() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfEdges() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit)
|
||||
throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> transpose() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> topologicalSort() throws UnsupportedOperationException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Collection<V>> stronglyConnectedComponents() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(Object... marker) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Edge<V, W>> distance(V source, V destination)
|
||||
throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
144
src/berack96/lib/graph/impl/ListGraph.java
Normal file
144
src/berack96/lib/graph/impl/ListGraph.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package berack96.lib.graph.impl;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An implementation of the graph using an adjacent list for representing the edges
|
||||
*
|
||||
* @param <V> the vertex
|
||||
* @param <W> the weight
|
||||
* @author Berack96
|
||||
*/
|
||||
public class ListGraph<V, W extends Number> extends AGraph<V, W> {
|
||||
|
||||
final private Map<V, List<Adj>> adj = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return adj.keySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Graph<V, W> getNewInstance() {
|
||||
return new ListGraph<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addVertex(V vertex) {
|
||||
adj.put(vertex, new LinkedList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean containsVertex(V vertex) {
|
||||
return adj.containsKey(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeVertex(V vertex) {
|
||||
adj.remove(vertex);
|
||||
adj.forEach((v, l) -> {
|
||||
Set<Adj> set = new HashSet<>();
|
||||
l.forEach(adj -> {
|
||||
if(adj.vertex.equals(vertex))
|
||||
set.add(adj);
|
||||
});
|
||||
l.removeAll(set);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeAllVertices() {
|
||||
adj.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
|
||||
if(!adj.containsKey(vertex1))
|
||||
return false;
|
||||
|
||||
for(Adj a : adj.get(vertex1))
|
||||
if(a.vertex.equals(vertex2))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
|
||||
W ret = null;
|
||||
List<Adj> l = adj.get(vertex1);
|
||||
for(Adj a : l)
|
||||
if(a.vertex.equals(vertex2)) {
|
||||
ret = a.weight;
|
||||
a.weight = weight;
|
||||
}
|
||||
if(ret == null)
|
||||
l.add(new Adj(vertex2, weight));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected W getWeightImpl(V vertex1, V vertex2) {
|
||||
W ret = null;
|
||||
for(Adj a : adj.get(vertex1))
|
||||
if(a.vertex.equals(vertex2))
|
||||
ret = a.weight;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Edge<V, W>> getEdgesOutImpl(V vertex) {
|
||||
Set<Edge<V,W>> set = new HashSet<>();
|
||||
adj.get(vertex).forEach(a -> set.add(new Edge<>(vertex, a.vertex, a.weight)));
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Edge<V, W>> getEdgesInImpl(V vertex) {
|
||||
Set<Edge<V,W>> set = new HashSet<>();
|
||||
adj.forEach((v, l) -> l.forEach(a -> {
|
||||
if(a.vertex.equals(vertex))
|
||||
set.add(new Edge<>(v, a.vertex, a.weight));
|
||||
}));
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeEdgeImpl(V vertex1, V vertex2) {
|
||||
Adj ret = null;
|
||||
List<Adj> l = adj.get(vertex1);
|
||||
for(Adj a : l)
|
||||
if(a.vertex.equals(vertex2))
|
||||
ret = a;
|
||||
l.remove(ret);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeAllOutEdgeImpl(V vertex) {
|
||||
adj.compute(vertex,(v, l) -> new LinkedList<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeAllInEdgeImpl(V vertex) {
|
||||
adj.forEach((v, l) -> {
|
||||
Set<Adj> set = new HashSet<>();
|
||||
l.forEach(adj -> {
|
||||
if(adj.vertex.equals(vertex))
|
||||
set.add(adj);
|
||||
});
|
||||
l.removeAll(set);
|
||||
});
|
||||
}
|
||||
|
||||
private class Adj {
|
||||
private final V vertex;
|
||||
private W weight;
|
||||
|
||||
private Adj(V vertex, W weight) {
|
||||
this.vertex = vertex;
|
||||
this.weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,10 @@
|
||||
package berack96.lib.graph.impl;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.Vertex;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.Dijkstra;
|
||||
import berack96.lib.graph.visit.impl.Tarjan;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Graph that uses HashMap for vertices and edges<br>
|
||||
@@ -23,7 +17,7 @@ import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
* @param <W> the weight of the edges
|
||||
* @author Berack96
|
||||
*/
|
||||
public class MapGraph<V, W extends Number> implements Graph<V, W> {
|
||||
public class MapGraph<V, W extends Number> extends AGraph<V, W> {
|
||||
|
||||
/**
|
||||
* Map that contains the edges from a vertex to another<br>
|
||||
@@ -31,321 +25,88 @@ public class MapGraph<V, W extends Number> implements Graph<V, W> {
|
||||
* If an edge exist, then it's weight is returned
|
||||
*/
|
||||
private final Map<V, Map<V, W>> edges = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Map that contains the marker as key and a set of all the vertices that has it as the value.<br>
|
||||
* This map is build like this for performance in creating the marker for multiple vertices.<br>
|
||||
* If you flip the parameters (object and set) then has more performance over the single vertex.
|
||||
*/
|
||||
private final Map<Object, Set<V>> markers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Need this variable for not calculating each time the SCC or the cyclic part if the graph doesn't change
|
||||
*/
|
||||
private Tarjan<V, W> tarjan = null;
|
||||
|
||||
/**
|
||||
* Need this variable for not calculating each time the distance from a vertex to all his destinations if the graph doesn't change
|
||||
*/
|
||||
private Map<V, Dijkstra<V, W>> dijkstra = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean isCyclic() {
|
||||
return stronglyConnectedComponents().size() != numberOfVertices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDAG() {
|
||||
return !isCyclic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
return new Vertex<>(this, vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addVertex(V vertex) throws NullPointerException {
|
||||
checkNull(vertex);
|
||||
edges.put(vertex, new HashMap<>());
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addVertexIfAbsent(V vertex) throws NullPointerException {
|
||||
if (contains(vertex))
|
||||
return false;
|
||||
addVertex(vertex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllVertices(Collection<V> vertices) throws NullPointerException {
|
||||
checkNull(vertices);
|
||||
vertices.forEach(this::addVertexIfAbsent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVertex(V vertex) throws NullPointerException {
|
||||
if (contains(vertex)) {
|
||||
edges.remove(vertex);
|
||||
edges.forEach((v, map) -> map.remove(vertex));
|
||||
markers.forEach((mark, set) -> set.remove(vertex));
|
||||
graphChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllVertex() {
|
||||
edges.clear();
|
||||
markers.clear();
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(V vertex) throws NullPointerException {
|
||||
checkNull(vertex);
|
||||
return edges.containsKey(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> marks() {
|
||||
Collection<Object> ret = new HashSet<>();
|
||||
markers.forEach((m, v) -> {
|
||||
if(v.size() > 0)
|
||||
ret.add(m);
|
||||
});
|
||||
|
||||
return ret;
|
||||
public Iterator<V> iterator() {
|
||||
return edges.keySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
checkNull(mark);
|
||||
|
||||
Set<V> set = markers.computeIfAbsent(mark, (v) -> new HashSet<>());
|
||||
set.add(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
checkNull(mark);
|
||||
markers.get(mark).remove(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
markers.forEach( (mark, set) -> set.remove(vertex) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
|
||||
checkNull(mark);
|
||||
return markers.computeIfAbsent(mark, (v) -> new HashSet<>());
|
||||
protected Graph<V, W> getNewInstance() {
|
||||
return new MapGraph<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addVertex(V vertex) {
|
||||
edges.put(vertex, new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean containsVertex(V vertex) {
|
||||
return edges.containsKey(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeVertex(V vertex) {
|
||||
edges.remove(vertex);
|
||||
edges.forEach((v, map) -> map.remove(vertex));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeAllVertices() {
|
||||
edges.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
|
||||
return contains(vertex1) && contains(vertex2) && edges.get(vertex1).containsKey(vertex2);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
|
||||
return edges.get(vertex1).put(vertex2, weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected W getWeightImpl(V vertex1, V vertex2) {
|
||||
return edges.get(vertex1).get(vertex2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
Collection<Object> marks = new HashSet<>();
|
||||
markers.forEach( (mark, set) -> {
|
||||
if (set.contains(vertex))
|
||||
marks.add(mark);
|
||||
});
|
||||
|
||||
return marks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll(Object mark) {
|
||||
checkNull(mark);
|
||||
markers.remove(mark);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll() {
|
||||
markers.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex1);
|
||||
checkNullAndExist(vertex2);
|
||||
checkNull(weight);
|
||||
|
||||
W old = edges.get(vertex1).put(vertex2, weight);
|
||||
graphChanged();
|
||||
return old;
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
return addEdge(edge.getSource(), edge.getDestination(), edge.getWeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
|
||||
addVertexIfAbsent(vertex1);
|
||||
addVertexIfAbsent(vertex2);
|
||||
return addEdge(vertex1, vertex2, weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
return addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
|
||||
edges.forEach((edge) -> addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex1);
|
||||
checkNullAndExist(vertex2);
|
||||
|
||||
return edges.get(vertex1).get(vertex2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex1);
|
||||
checkNullAndExist(vertex2);
|
||||
|
||||
edges.get(vertex1).remove(vertex2);
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
edges.forEach((v, map) -> map.remove(vertex));
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
edges.put(vertex, new HashMap<>());
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
removeVertex(vertex);
|
||||
addVertex(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge() {
|
||||
edges.forEach((v, map) -> map.clear());
|
||||
graphChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
|
||||
return (contains(vertex1) && contains(vertex2)) && edges.get(vertex1).get(vertex2) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> vertices() {
|
||||
return new HashSet<>(edges.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edges() {
|
||||
Set<Edge<V, W>> allEdges = new HashSet<>();
|
||||
edges.forEach((source, map) -> map.forEach((destination, weight) -> allEdges.add(new Edge<>(source, destination, weight))));
|
||||
return allEdges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
Set<Edge<V, W>> set = new HashSet<>();
|
||||
edges.forEach((source, map) -> map.forEach((destination, weight) -> {
|
||||
if (destination.equals(vertex) || source.equals(vertex))
|
||||
set.add(new Edge<>(source, destination, weight));
|
||||
}));
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
protected Collection<Edge<V, W>> getEdgesOutImpl(V vertex) {
|
||||
Collection<Edge<V, W>> collection = new HashSet<>();
|
||||
edges.get(vertex).forEach((dest, weight) -> collection.add(new Edge<>(vertex, dest, weight)));
|
||||
return collection;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Edge<V, W>> getEdgesInImpl(V vertex) {
|
||||
Collection<Edge<V, W>> collection = new HashSet<>();
|
||||
edges.forEach((source, edge) -> {
|
||||
if (edge.get(vertex) != null)
|
||||
collection.add(new Edge<>(source, vertex, edge.get(vertex)));
|
||||
});
|
||||
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
Collection<Edge<V, W>> collection = new HashSet<>();
|
||||
edges.get(vertex).forEach((dest, weight) -> collection.add(new Edge<>(vertex, dest, weight)));
|
||||
@Override
|
||||
protected void removeEdgeImpl(V vertex1, V vertex2) {
|
||||
edges.get(vertex1).remove(vertex2);
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
@Override
|
||||
protected void removeAllOutEdgeImpl(V vertex) {
|
||||
edges.put(vertex, new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
return new HashSet<>(edges.get(vertex).keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
Set<V> set = new HashSet<>();
|
||||
edges.forEach((v, map) -> {
|
||||
if (map.containsKey(vertex)) set.add(v);
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
AtomicInteger sum = new AtomicInteger();
|
||||
edges.forEach((v, map) -> {
|
||||
if (map.containsKey(vertex))
|
||||
sum.getAndIncrement();
|
||||
});
|
||||
|
||||
return sum.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(vertex);
|
||||
|
||||
return edges.get(vertex).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
return degreeIn(vertex) + degreeOut(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfVertices() {
|
||||
@Override
|
||||
protected void removeAllInEdgeImpl(V vertex) {
|
||||
edges.forEach((v, map) -> map.remove(vertex));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return edges.size();
|
||||
}
|
||||
|
||||
@@ -356,189 +117,4 @@ public class MapGraph<V, W extends Number> implements Graph<V, W> {
|
||||
|
||||
return sum.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
|
||||
return strategy.visit(this, source, visit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> transpose() {
|
||||
Graph<V, W> graph = new MapGraph<>();
|
||||
for (V vertex : edges.keySet())
|
||||
graph.addVertex(vertex);
|
||||
|
||||
edges.forEach((source, map) -> map.forEach((destination, weight) -> graph.addEdge(destination, source, weight)));
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> topologicalSort() throws UnsupportedOperationException {
|
||||
if (!isDAG())
|
||||
throw new UnsupportedOperationException(NOT_DAG);
|
||||
return getTarjan().getTopologicalSort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Collection<V>> stronglyConnectedComponents() {
|
||||
return getTarjan().getSCC();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
|
||||
Graph<V, W> sub = new MapGraph<>();
|
||||
Set<V> vertices = new HashSet<>();
|
||||
|
||||
int finalDepth = depth > 0 ? depth : 0;
|
||||
VisitStrategy<V, W> strategy = (graph, sourceVertex, visit) -> {
|
||||
int currentDepth = 0;
|
||||
final LinkedList<Map.Entry<V, Integer>> toVisitChildren = new LinkedList<>();
|
||||
toVisitChildren.add(new AbstractMap.SimpleEntry<>(sourceVertex, 0));
|
||||
vertices.add(source);
|
||||
|
||||
while (!toVisitChildren.isEmpty() && currentDepth + 1 <= finalDepth) {
|
||||
final Map.Entry<V, Integer> current = toVisitChildren.removeFirst();
|
||||
currentDepth = current.getValue() + 1;
|
||||
final int finalCurrentDepth = currentDepth;
|
||||
|
||||
for (V child : graph.getChildren(current.getKey()))
|
||||
if (!vertices.contains(child)) {
|
||||
toVisitChildren.addLast(new AbstractMap.SimpleEntry<>(child, finalCurrentDepth));
|
||||
vertices.add(child);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
strategy.visit(this, source, null);
|
||||
|
||||
sub.addAllVertices(vertices);
|
||||
for (V vertex : vertices)
|
||||
getEdgesOut(vertex).forEach((edge) -> {
|
||||
try {
|
||||
sub.addEdge(edge);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
});
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(final Object...marker) {
|
||||
final Graph<V, W> sub = new MapGraph<>();
|
||||
final Set<V> allVertices = new HashSet<>();
|
||||
final Set<Object> allMarkers = new HashSet<>();
|
||||
final boolean isEmpty = (marker == null || marker.length == 0);
|
||||
|
||||
if (!isEmpty)
|
||||
for (Object mark: marker)
|
||||
allMarkers.add(mark);
|
||||
|
||||
markers.forEach( (mark, set) -> {
|
||||
if (isEmpty || allMarkers.contains(mark))
|
||||
allVertices.addAll(set);
|
||||
});
|
||||
|
||||
if (isEmpty) {
|
||||
Collection<V> toAdd = vertices();
|
||||
toAdd.removeAll(allVertices);
|
||||
allVertices.clear();
|
||||
allVertices.addAll(toAdd);
|
||||
}
|
||||
|
||||
sub.addAllVertices(allVertices);
|
||||
for (V vertex : sub.vertices())
|
||||
edges.get(vertex).forEach( (dest, weight) -> {
|
||||
try {
|
||||
sub.addEdge(vertex, dest, weight);
|
||||
} catch (Exception ignored) {}
|
||||
});
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Edge<V, W>> distance(V source, V destination) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
|
||||
checkNullAndExist(source);
|
||||
checkNullAndExist(destination);
|
||||
|
||||
Dijkstra<V, W> dijkstra = getDijkstra(source); /* Cached */
|
||||
List<Edge<V, W>> path = dijkstra.getLastDistance().get(destination);
|
||||
if (path == null)
|
||||
throw new UnsupportedOperationException(NOT_CONNECTED);
|
||||
return new ArrayList<>(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
|
||||
checkNullAndExist(source);
|
||||
return new HashMap<>(getDijkstra(source).getLastDistance()); /* Cached */
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return edges.keySet().iterator();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple function that reset all the caching variables if the graph changed
|
||||
*/
|
||||
private void graphChanged() {
|
||||
tarjan = null;
|
||||
dijkstra.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple function that return the result of the Dijkstra visit, with the starting point as source.<br>
|
||||
* It also cache it, so multiple call will return always the same value unless the graph has changed.
|
||||
* @param source the source of the visit
|
||||
* @return the complete visit
|
||||
*/
|
||||
private Dijkstra<V, W> getDijkstra(V source) {
|
||||
if (dijkstra.get(source) == null) {
|
||||
Dijkstra<V, W> newDijkstra = new Dijkstra<>();
|
||||
newDijkstra.visit(this, source, null);
|
||||
dijkstra.put(source, newDijkstra);
|
||||
}
|
||||
|
||||
return dijkstra.get(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple function that return the result of the Tarjan visit.<br>
|
||||
* It also cache it, so multiple call will return always the same value unless the graph has changed.
|
||||
* @return the tarjan visit
|
||||
*/
|
||||
private Tarjan<V, W> getTarjan() {
|
||||
if (tarjan == null) {
|
||||
tarjan = new Tarjan<>();
|
||||
tarjan.visit(this, null, null);
|
||||
}
|
||||
|
||||
return tarjan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the object passed is null.
|
||||
* If it is throw an exception.
|
||||
* @param object the object to test
|
||||
*/
|
||||
private void checkNull(Object object) {
|
||||
if (object == null)
|
||||
throw new NullPointerException(PARAM_NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the vertex passed is null and if exist in the graph.
|
||||
* If not then throws eventual exception
|
||||
* @param vertex the vertex to test
|
||||
*/
|
||||
private void checkNullAndExist(V vertex) {
|
||||
checkNull(vertex);
|
||||
if (!edges.containsKey(vertex))
|
||||
throw new IllegalArgumentException(VERTEX_NOT_CONTAINED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,319 +1,132 @@
|
||||
package berack96.lib.graph.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.Vertex;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
public class MatrixGraph<V, W extends Number> implements Graph<V, W> {
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* An implementation of the graph using a matrix for representing the edges
|
||||
*
|
||||
* @param <V> the vertex
|
||||
* @param <W> the weight
|
||||
* @author Berack96
|
||||
*/
|
||||
public class MatrixGraph<V, W extends Number> extends AGraph<V, W> {
|
||||
|
||||
final Map<V, Integer> map = new HashMap<>();
|
||||
final List<List<W>> matrix = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
return map.keySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCyclic() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
protected Graph<V, W> getNewInstance() {
|
||||
return new MatrixGraph<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDAG() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
protected void addVertex(V vertex) {
|
||||
map.put(vertex, map.size());
|
||||
|
||||
List<W> newVert = new ArrayList<>(map.size());
|
||||
for (int i=0; i<map.size(); i++)
|
||||
newVert.add(null);
|
||||
|
||||
matrix.forEach(list -> list.add(null));
|
||||
matrix.add(newVert);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vertex<V> getVertex(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
protected boolean containsVertex(V vertex) {
|
||||
return map.containsKey(vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addVertex(V vertex) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
protected void removeVertex(V vertex) {
|
||||
int x = map.remove(vertex);
|
||||
map.replaceAll((vert, index) -> index>x? index-1:index);
|
||||
|
||||
matrix.remove(x);
|
||||
matrix.forEach(list -> {
|
||||
int i;
|
||||
for(i=x; i<list.size()-1; i++)
|
||||
list.set(i, list.get(i+1));
|
||||
if(--i>0)
|
||||
list.remove(i);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addVertexIfAbsent(V vertex) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
protected void removeAllVertices() {
|
||||
map.clear();
|
||||
matrix.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllVertices(Collection<V> vertices) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
|
||||
try {
|
||||
return matrix.get(map.get(vertex1)).get(map.get(vertex2)) != null;
|
||||
} catch (Exception ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVertex(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
|
||||
return matrix.get(map.get(vertex1)).set(map.get(vertex2), weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllVertex() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
protected W getWeightImpl(V vertex1, V vertex2) {
|
||||
return matrix.get(map.get(vertex1)).get(map.get(vertex2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(V vertex) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
protected Collection<Edge<V, W>> getEdgesOutImpl(V vertex) {
|
||||
Set<Edge<V,W>> set = new HashSet<>();
|
||||
Map<Integer, V> inverted = new HashMap<>();
|
||||
map.keySet().forEach(v -> inverted.put(map.get(v), v));
|
||||
|
||||
List<W> list = matrix.get(map.get(vertex));
|
||||
for(int i=0; i<list.size(); i++) {
|
||||
W weight = list.get(i);
|
||||
if (weight != null)
|
||||
set.add(new Edge<>(vertex, inverted.get(i), weight));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> marks() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
protected Collection<Edge<V, W>> getEdgesInImpl(V vertex) {
|
||||
Set<Edge<V,W>> set = new HashSet<>();
|
||||
Map<Integer, V> inverted = new HashMap<>();
|
||||
map.keySet().forEach(v -> inverted.put(map.get(v), v));
|
||||
|
||||
int x = map.get(vertex);
|
||||
for(int i=0; i<matrix.size(); i++) {
|
||||
W weight = matrix.get(i).get(x);
|
||||
if (weight != null)
|
||||
set.add(new Edge<>(inverted.get(i), vertex, weight));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
protected void removeEdgeImpl(V vertex1, V vertex2) {
|
||||
matrix.get(map.get(vertex1)).set(map.get(vertex2), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
protected void removeAllOutEdgeImpl(V vertex) {
|
||||
matrix.get(map.get(vertex)).replaceAll(var -> null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
protected void removeAllInEdgeImpl(V vertex) {
|
||||
int x = map.get(vertex);
|
||||
matrix.forEach(list -> list.set(x, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getMarkedWith(Object mark) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll(Object mark) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unMarkAll() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEdge() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> vertices() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edges() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfVertices() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int numberOfEdges() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit)
|
||||
throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> transpose() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<V> topologicalSort() throws UnsupportedOperationException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Collection<V>> stronglyConnectedComponents() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graph<V, W> subGraph(Object... marker) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Edge<V, W>> distance(V source, V destination)
|
||||
throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ package berack96.lib.graph.models;
|
||||
*
|
||||
*/
|
||||
public class EdgeSaveStructure {
|
||||
public EdgeSaveStructure() {}
|
||||
protected EdgeSaveStructure(String s, String d, String w) {
|
||||
this.src = s;
|
||||
this.dest = d;
|
||||
|
||||
@@ -2,6 +2,14 @@ package berack96.lib.graph.models;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Support class used for saving a Graph in a file.
|
||||
@@ -9,33 +17,97 @@ import berack96.lib.graph.Graph;
|
||||
* @author Berack96
|
||||
*
|
||||
*/
|
||||
public class GraphSaveStructure {
|
||||
public GraphSaveStructure() {}
|
||||
public GraphSaveStructure(Graph<?, ?> graph, String other) {
|
||||
this.vertices = new String[graph.numberOfVertices()];
|
||||
int i = 0;
|
||||
for(Object o: graph.vertices()) {
|
||||
this.vertices[i] = Graph.GSON.toJson(o);
|
||||
i++;
|
||||
}
|
||||
|
||||
this.edges = new EdgeSaveStructure[graph.numberOfEdges()];
|
||||
i = 0;
|
||||
for (Edge<?, ?> edge : graph.edges()) {
|
||||
this.edges[i] = new EdgeSaveStructure(
|
||||
Graph.GSON.toJson(edge.getSource()),
|
||||
Graph.GSON.toJson(edge.getDestination()),
|
||||
Graph.GSON.toJson(edge.getWeight())
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
public class GraphSaveStructure<V, W extends Number> {
|
||||
|
||||
final public Gson gson = new Gson();
|
||||
public String[] vertices;
|
||||
public EdgeSaveStructure[] edges;
|
||||
//public MarkSaveStructure[] marks;
|
||||
public String other;
|
||||
|
||||
/*
|
||||
* Load the graph saved in this class in an instance of a graph passed.
|
||||
* Before loading the graph, it is emptied.
|
||||
*/
|
||||
public final void load(Graph<V, W> graph, String fileName, Class<V> classV, Class<W> classW) throws FileNotFoundException {
|
||||
Gson gson = new GsonBuilder().registerTypeAdapter(this.getClass(), new Creator(this)).create();
|
||||
JsonReader reader = new JsonReader(new FileReader(fileName));
|
||||
gson.fromJson(reader, this.getClass());
|
||||
loadGraph(graph, classV, classW);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used by sub-classes for saving other stuff from the graph
|
||||
*
|
||||
* @param graph the graph to load with
|
||||
* @param classV the class used for the Vertex
|
||||
* @param classW the class used for the Weight
|
||||
* @throws NullPointerException if the graph is null
|
||||
* @throws JsonSyntaxException if the file is malformed or corrupted
|
||||
*/
|
||||
protected void loadGraph(Graph<V, W> graph, Class<V> classV, Class<W> classW) throws NullPointerException, JsonSyntaxException {
|
||||
graph.removeAll();
|
||||
for(String str : vertices)
|
||||
graph.add(gson.fromJson(str, classV));
|
||||
|
||||
for (EdgeSaveStructure edge : edges)
|
||||
graph.addEdge(
|
||||
gson.fromJson(edge.src, classV),
|
||||
gson.fromJson(edge.dest, classV),
|
||||
gson.fromJson(edge.weight, classW)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Save the Graph passed as input to a file inserted as parameter.<br>
|
||||
* The resulting file is a Json string representing all the graph.<br>
|
||||
* If the directory for getting through the file do not exist,<br>
|
||||
* then it is created.<br>
|
||||
* Marks are not included.<br>
|
||||
* The additional parameter is used if you want to save other as well as the graph.
|
||||
*
|
||||
* @param graph the graph to save
|
||||
* @param file the name of the file
|
||||
* @throws IOException for various reason that appear in the message, but the most common is that the file is not found.
|
||||
*/
|
||||
public final void save(Graph<V,W> graph, String file) throws IOException {
|
||||
saveGraph(graph);
|
||||
int slash = file.lastIndexOf("\\");
|
||||
if(slash == -1)
|
||||
slash = file.lastIndexOf("/");
|
||||
if(slash != -1) {
|
||||
String dir = file.substring(0, slash);
|
||||
File fDir = new File(dir);
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
fDir.mkdirs();
|
||||
}
|
||||
|
||||
FileWriter writer = new FileWriter(file);
|
||||
gson.toJson(this, writer);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used by sub-classes for saving other stuff from the graph
|
||||
* @param graph the graph to save
|
||||
*/
|
||||
protected void saveGraph(Graph<V,W> graph) {
|
||||
this.vertices = new String[graph.size()];
|
||||
int i = 0;
|
||||
for(Object o: graph.vertices())
|
||||
this.vertices[i++] = gson.toJson(o);
|
||||
|
||||
this.edges = new EdgeSaveStructure[graph.numberOfEdges()];
|
||||
i = 0;
|
||||
for (Edge<?, ?> edge : graph.edges())
|
||||
this.edges[i++] = new EdgeSaveStructure(
|
||||
gson.toJson(edge.getSource()),
|
||||
gson.toJson(edge.getDestination()),
|
||||
gson.toJson(edge.getWeight())
|
||||
);
|
||||
}
|
||||
|
||||
private class Creator implements InstanceCreator<GraphSaveStructure<V,W>> {
|
||||
private final GraphSaveStructure<V,W> save;
|
||||
public Creator(GraphSaveStructure<V,W> save) { this.save = save; }
|
||||
public GraphSaveStructure<V,W> createInstance(Type type) { return save; }
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ package berack96.lib.graph.models;
|
||||
*
|
||||
*/
|
||||
public class MarkSaveStructure {
|
||||
public MarkSaveStructure() {}
|
||||
protected MarkSaveStructure(String v, Object m) {
|
||||
this.vert = v;
|
||||
this.mark = m;
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
package berack96.lib.graph.view;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.BevelBorder;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.view.edge.EdgeListener;
|
||||
import berack96.lib.graph.view.vertex.VertexListener;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.BevelBorder;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.Serial;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Map<String, VisitListener<V>> visits;
|
||||
|
||||
@@ -43,7 +33,7 @@ public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
|
||||
/* FIRST (GRAPH INFO) */
|
||||
|
||||
JLabel vNumber = new JLabel(String.valueOf(graphPanel.getGraph().numberOfVertices()));
|
||||
JLabel vNumber = new JLabel(String.valueOf(graphPanel.getGraph().size()));
|
||||
JLabel eNumber = new JLabel(String.valueOf(graphPanel.getGraph().numberOfEdges()));
|
||||
JLabel gCyclic = new JLabel(String.valueOf(graphPanel.getGraph().isCyclic()));
|
||||
|
||||
@@ -194,7 +184,7 @@ public class GraphInfo<V, W extends Number> extends JPanel {
|
||||
graphPanel.addObserver((o, arg) -> {
|
||||
Graph<V, W> graph = graphPanel.getGraph();
|
||||
if(arg.equals(graph)) {
|
||||
vNumber.setText(String.valueOf(graph.numberOfVertices()));
|
||||
vNumber.setText(String.valueOf(graph.size()));
|
||||
eNumber.setText(String.valueOf(graph.numberOfEdges()));
|
||||
gCyclic.setText(String.valueOf(graph.isCyclic()));
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@ public interface GraphListener extends MouseListener, MouseMotionListener, KeyLi
|
||||
* This function is called when the listener is removed to the graph.
|
||||
* Here you could remove any other thing that you have done.
|
||||
*/
|
||||
public void remove();
|
||||
void remove();
|
||||
|
||||
/**
|
||||
* Get the description of this listener, in a way to interact with the user.
|
||||
*
|
||||
* @return a string describing the functionalities of this listener
|
||||
*/
|
||||
public String getDescription();
|
||||
String getDescription();
|
||||
}
|
||||
|
||||
@@ -1,23 +1,5 @@
|
||||
package berack96.lib.graph.view;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.Vertex;
|
||||
@@ -25,17 +7,29 @@ import berack96.lib.graph.impl.MapGraph;
|
||||
import berack96.lib.graph.view.edge.EdgeComponent;
|
||||
import berack96.lib.graph.view.vertex.VertexComponent;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.io.IOException;
|
||||
import java.io.Serial;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Observer;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings({"unchecked", "deprecation"})
|
||||
public class GraphPanel<V, W extends Number> extends Component {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final GraphicalView<VertexComponent<V>> vertexRender;
|
||||
private final GraphicalView<EdgeComponent<V, W>> edgeRender;
|
||||
private final Class<V> classV;
|
||||
private final Class<W> classW;
|
||||
|
||||
private final Container vertices = new Container();
|
||||
private final Container edges = new Container();
|
||||
final Container vertices = new Container();
|
||||
final Container edges = new Container();
|
||||
|
||||
private final Graph<V, W> graph = new MapGraph<>();
|
||||
private final Set<Observer> observers = new HashSet<>();
|
||||
@@ -78,8 +72,10 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
boolean isContained = false;
|
||||
|
||||
for(Component comp : vertices.getComponents())
|
||||
if (comp.equals(v))
|
||||
isContained = true;
|
||||
if (comp.equals(v)) {
|
||||
isContained = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isContained) {
|
||||
v.setBounds(vertexRender.getBox(v, center));
|
||||
@@ -122,8 +118,8 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
edgeComponent.setBounds(edgeRender.getBox(edgeComponent, center));
|
||||
edges.add(edgeComponent);
|
||||
graph.addEdge(edgeComponent.edge);
|
||||
} catch (Exception ignore) {
|
||||
ignore.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,26 +161,11 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
}
|
||||
|
||||
public void save(String fileName) throws IOException {
|
||||
GraphGraphicalSave save = new GraphGraphicalSave(vertices);
|
||||
Graph.save(graph, Graph.GSON.toJson(save), fileName);
|
||||
new GraphPointsSave<>(this).save(graph, fileName);
|
||||
}
|
||||
|
||||
public void load(String fileName) throws IOException {
|
||||
String saveContent = Graph.load(graph, fileName, classV, classW);
|
||||
GraphGraphicalSave save = Graph.GSON.fromJson(saveContent, GraphGraphicalSave.class);
|
||||
vertices.removeAll();
|
||||
edges.removeAll();
|
||||
|
||||
for(int i = 0; i<save.vertices.length; i++) {
|
||||
V v = Graph.GSON.fromJson(save.vertices[i], classV);
|
||||
Point p = save.points[i];
|
||||
addVertex(p, v);
|
||||
}
|
||||
|
||||
for(String v : save.vertices)
|
||||
graph.getEdgesOut(Graph.GSON.fromJson(v, classV)).forEach(e -> addEdge(e));
|
||||
|
||||
repaint();
|
||||
new GraphPointsSave<>(this).load(graph, fileName, classV, classW);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -229,37 +210,5 @@ public class GraphPanel<V, W extends Number> extends Component {
|
||||
observers.forEach(observer -> observer.update(null, this.graph));
|
||||
}
|
||||
|
||||
class GraphGraphicalSave {
|
||||
public GraphGraphicalSave() {}
|
||||
protected GraphGraphicalSave(Container vertices) {
|
||||
List<String> v = new LinkedList<>();
|
||||
List<Point> p = new LinkedList<>();
|
||||
|
||||
for(Component vertex : vertices.getComponents()) {
|
||||
Point temp = new Point(vertex.getX(), vertex.getY());
|
||||
temp.x += vertex.getWidth() / 2;
|
||||
temp.y += vertex.getHeight() / 2;
|
||||
|
||||
p.add(temp);
|
||||
v.add(Graph.GSON.toJson(((VertexComponent<V>) vertex).vertex.getValue()));
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
this.vertices = new String[v.size()];
|
||||
for(String s : v) {
|
||||
this.vertices[i] = s;
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
this.points = new Point[p.size()];
|
||||
for(Point pt : p) {
|
||||
this.points[i] = pt;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public String[] vertices;
|
||||
public Point[] points;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
54
src/berack96/lib/graph/view/GraphPointsSave.java
Normal file
54
src/berack96/lib/graph/view/GraphPointsSave.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package berack96.lib.graph.view;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.models.GraphSaveStructure;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class GraphPointsSave<V, W extends Number> extends GraphSaveStructure<V, W> {
|
||||
|
||||
final private GraphPanel<V,W> panel;
|
||||
public Point[] points;
|
||||
|
||||
public GraphPointsSave(GraphPanel<V,W> panel) {
|
||||
this.panel = panel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveGraph(Graph<V, W> graph) {
|
||||
super.saveGraph(graph);
|
||||
List<Point> p = new LinkedList<>();
|
||||
|
||||
for(Component vertex : panel.vertices.getComponents()) {
|
||||
Point temp = new Point(vertex.getX(), vertex.getY());
|
||||
temp.x += vertex.getWidth() / 2;
|
||||
temp.y += vertex.getHeight() / 2;
|
||||
p.add(temp);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
this.points = new Point[p.size()];
|
||||
for(Point pt : p)
|
||||
this.points[i++] = pt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadGraph(Graph<V, W> graph, Class<V> classV, Class<W> classW) {
|
||||
super.loadGraph(graph, classV, classW);
|
||||
|
||||
panel.vertices.removeAll();
|
||||
panel.edges.removeAll();
|
||||
|
||||
for(int i = 0; i<vertices.length; i++) {
|
||||
V v = gson.fromJson(vertices[i], classV);
|
||||
Point p = points[i];
|
||||
panel.addVertex(p, v);
|
||||
}
|
||||
|
||||
for(String v : vertices)
|
||||
graph.getEdgesOut(gson.fromJson(v, classV)).forEach(panel::addEdge);
|
||||
panel.repaint();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
package berack96.lib.graph.view;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import berack96.lib.graph.view.edge.EdgeListener;
|
||||
import berack96.lib.graph.view.vertex.VertexListener;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
@@ -14,6 +8,12 @@ import berack96.lib.graph.visit.impl.DFS;
|
||||
import berack96.lib.graph.visit.impl.Dijkstra;
|
||||
import berack96.lib.graph.visit.impl.Tarjan;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.Serial;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class is the Window that appear for building the graph and playing around with it
|
||||
*
|
||||
@@ -21,10 +21,10 @@ import berack96.lib.graph.visit.impl.Tarjan;
|
||||
*/
|
||||
public class GraphWindow<V, W extends Number> extends JFrame {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final GraphPanel<V, W> graphPanel;
|
||||
private final GraphInfo<V, W> infoPanel;
|
||||
|
||||
public GraphWindow(GraphPanel<V, W> graphPanel, VertexListener<V> vListener, EdgeListener<V, W> eListener) {
|
||||
this.setTitle("Grafo");
|
||||
@@ -37,14 +37,14 @@ public class GraphWindow<V, W extends Number> extends JFrame {
|
||||
strats.add(new Dijkstra<>());
|
||||
strats.add(new Tarjan<>());
|
||||
|
||||
this.infoPanel = new GraphInfo<>(graphPanel, vListener, eListener, strats);
|
||||
GraphInfo<V, W> infoPanel = new GraphInfo<>(graphPanel, vListener, eListener, strats);
|
||||
this.graphPanel = graphPanel;
|
||||
this.add(infoPanel, BorderLayout.EAST);
|
||||
this.add(graphPanel);
|
||||
}
|
||||
|
||||
public void visitRefresh(int millisec) {
|
||||
VisitListener.changeRefresh(millisec);
|
||||
public void visitRefresh(int millis) {
|
||||
VisitListener.changeRefresh(millis);
|
||||
}
|
||||
|
||||
public GraphPanel<V, W> getGraphPanel() {
|
||||
|
||||
@@ -25,13 +25,13 @@ public class VisitListener<V> implements GraphListener {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
public static void changeRefresh(int millisec) {
|
||||
refreshTime = millisec;
|
||||
public static void changeRefresh(int mills) {
|
||||
refreshTime = mills;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
timers.forEach(t -> t.stop());
|
||||
timers.forEach(Timer::stop);
|
||||
timers.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package berack96.lib.graph.view.vertex;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import berack96.lib.graph.Vertex;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.Serial;
|
||||
|
||||
public class VertexComponent<V> extends Component {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public final Vertex<V> vertex;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package berack96.lib.graph.view.vertex;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.view.GraphPanel;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class VertexIntListener extends VertexListener<Integer> {
|
||||
|
||||
public VertexIntListener(GraphPanel<Integer, ?> panel) {
|
||||
@@ -17,14 +17,14 @@ public class VertexIntListener extends VertexListener<Integer> {
|
||||
@Override
|
||||
protected Integer buildNewVertex(Graph<Integer, ?> graph) {
|
||||
int counter = 0;
|
||||
Integer[] vertices = graph.vertices().toArray(new Integer[graph.numberOfVertices()]);
|
||||
Integer[] vertices = graph.vertices().toArray(new Integer[graph.size()]);
|
||||
Arrays.sort(vertices);
|
||||
|
||||
for(int i = 0; i<vertices.length; i++) {
|
||||
if(!vertices[i].equals(counter))
|
||||
return counter;
|
||||
counter++;
|
||||
}
|
||||
|
||||
for (Integer vertex : vertices) {
|
||||
if (!vertex.equals(counter))
|
||||
return counter;
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package berack96.lib.graph.view.vertex;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
import berack96.lib.graph.view.GraphicalView;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class VertexView<V> implements GraphicalView<VertexComponent<V>> {
|
||||
|
||||
private static final Font FONT = new Font("Comic Sans MS", Font.BOLD, 17);
|
||||
@@ -23,7 +23,7 @@ public class VertexView<V> implements GraphicalView<VertexComponent<V>> {
|
||||
boolean discovered = obj.vertex.getMarks().contains("discovered");
|
||||
boolean visited = obj.vertex.getMarks().contains("visited");
|
||||
boolean selected = obj.vertex.getMarks().contains("selected");
|
||||
|
||||
|
||||
FontMetrics metrics = obj.getFontMetrics(FONT);
|
||||
int stringPixels = metrics.stringWidth(obj.vertex.getValue().toString());
|
||||
int size = Math.max(stringPixels, metrics.getHeight()) + 2 * PADDING;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package berack96.lib.graph.visit.impl;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Breadth-first search<br>
|
||||
* The algorithm starts at the root node and explores all of the neighbor nodes at the present depth prior to moving on to the nodes at the next depth level.
|
||||
@@ -29,7 +29,7 @@ public class BFS<V, W extends Number> implements VisitStrategy<V, W> {
|
||||
while (!toVisitChildren.isEmpty()) {
|
||||
V current = toVisitChildren.removeFirst();
|
||||
|
||||
for (V child : graph.getChildren(current))
|
||||
for (V child : graph.getChildrens(current))
|
||||
if (!info.isDiscovered(child)) {
|
||||
toVisitChildren.addLast(child);
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package berack96.lib.graph.visit.impl;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Stack;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
|
||||
/**
|
||||
* Depth-first search<br>
|
||||
* The algorithm starts at the root node and explores as far as possible along each branch before backtracking.
|
||||
@@ -27,7 +27,7 @@ public class DFS<V, W extends Number> implements VisitStrategy<V, W> {
|
||||
while (!toVisit.isEmpty()) {
|
||||
V current = toVisit.peek();
|
||||
boolean hasChildToVisit = false;
|
||||
Iterator<V> iter = graph.getChildren(current).iterator();
|
||||
Iterator<V> iter = graph.getChildrens(current).iterator();
|
||||
|
||||
while (iter.hasNext() && !hasChildToVisit) {
|
||||
V child = iter.next();
|
||||
|
||||
53
src/berack96/lib/graph/visit/impl/Depth.java
Normal file
53
src/berack96/lib/graph/visit/impl/Depth.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package berack96.lib.graph.visit.impl;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Depth<V, W extends Number> implements VisitStrategy<V, W> {
|
||||
|
||||
private long finalDepth;
|
||||
|
||||
public Depth(long depth) {
|
||||
this.finalDepth = depth;
|
||||
}
|
||||
|
||||
public void setDepth(long depth) {
|
||||
this.finalDepth = depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitInfo<V> visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
|
||||
VisitInfo<V> info = new VisitInfo<>(source);
|
||||
long currentDepth = info.getDepth(source);
|
||||
|
||||
if(visit != null)
|
||||
visit.accept(source);
|
||||
info.setVisited(source);
|
||||
|
||||
List<V> toVisit = new LinkedList<>();
|
||||
toVisit.add(source);
|
||||
|
||||
while (!toVisit.isEmpty() && currentDepth < finalDepth) {
|
||||
V current = toVisit.remove(0);
|
||||
currentDepth = info.getDepth(current) + 1;
|
||||
|
||||
for (V child : graph.getChildrens(current))
|
||||
if (!info.isDiscovered(child)) {
|
||||
if(visit != null)
|
||||
visit.accept(child);
|
||||
|
||||
info.setVisited(child);
|
||||
info.setParent(current, child);
|
||||
toVisit.add(child);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package berack96.lib.graph.visit.impl;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.visit.VisitSCC;
|
||||
import berack96.lib.graph.visit.VisitTopological;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Class that implements the Tarjan algorithm and uses it for getting the SCC and the topological sort
|
||||
*
|
||||
@@ -61,7 +61,7 @@ public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopolog
|
||||
strongConnect(graph, vertex, index, visit);
|
||||
}
|
||||
|
||||
topologicalSort = (graph.numberOfVertices() == SCC.size()) ? new ArrayList<>(topologicalSort) : null;
|
||||
topologicalSort = (graph.size() == SCC.size()) ? new ArrayList<>(topologicalSort) : null;
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopolog
|
||||
info.setDiscovered(vertex);
|
||||
|
||||
// Consider successors of v
|
||||
for (V child : graph.getChildren(vertex)) {
|
||||
for (V child : graph.getChildrens(vertex)) {
|
||||
if (!indices.containsKey(child)) {
|
||||
info.setParent(vertex, child);
|
||||
strongConnect(graph, child, index, visit);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package berack96.lib.graph.visit.impl;
|
||||
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import berack96.lib.graph.visit.VisitStrategy;
|
||||
|
||||
/**
|
||||
* The class used for getting the info of the visit.<br>
|
||||
* It could be used with the algorithm of the visit for set some useful data.
|
||||
@@ -13,9 +13,9 @@ import berack96.lib.graph.visit.VisitStrategy;
|
||||
* @author Berack96
|
||||
*/
|
||||
public class VisitInfo<V> {
|
||||
private final Map<V, Long> discovered;
|
||||
private final Map<V, Long> visited;
|
||||
private final Map<V, V> parent;
|
||||
private static final int NOT_SET = -1;
|
||||
|
||||
private final Map<V, VertexInfo> vertices;
|
||||
private final V source;
|
||||
private long time;
|
||||
|
||||
@@ -29,118 +29,12 @@ public class VisitInfo<V> {
|
||||
if (source == null)
|
||||
throw new NullPointerException();
|
||||
|
||||
discovered = new Hashtable<>();
|
||||
visited = new Hashtable<>();
|
||||
parent = new Hashtable<>();
|
||||
|
||||
this.vertices = new Hashtable<>();
|
||||
this.time = 0;
|
||||
this.source = source;
|
||||
setDiscovered(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* The time of the vertex when it is discovered in the visit.<br>
|
||||
* For "discovered" i mean when the node is first found by the visit algorithm. It may depends form {@link VisitStrategy}<br>
|
||||
* The time starts at 0 and for each vertex discovered it is increased by one. If a vertex is visited it also increase the time<br>
|
||||
*
|
||||
* @param vertex the vertex needed
|
||||
* @return the time of it's discovery
|
||||
* @throws IllegalArgumentException if the vertex is not discovered
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
public long getTimeDiscover(V vertex) throws IllegalArgumentException, NullPointerException {
|
||||
Long time = discovered.get(vertex);
|
||||
if (time == null)
|
||||
throw new IllegalArgumentException();
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* The time when the vertex is visited by the algorithm<br>
|
||||
* For "visited" i mean when the node is finally visited by the visit algorithm. It may depends form {@link VisitStrategy}<br>
|
||||
* The time starts at 0 and for each vertex discovered or visited is increased by one<br>
|
||||
*
|
||||
* @param vertex the vertex needed
|
||||
* @return the time of it's visit
|
||||
* @throws IllegalArgumentException if the vertex is not visited
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
public long getTimeVisit(V vertex) throws IllegalArgumentException, NullPointerException {
|
||||
Long time = visited.get(vertex);
|
||||
if (time == null)
|
||||
throw new IllegalArgumentException();
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a vertex is discovered or not
|
||||
*
|
||||
* @param vertex the vertex chosen
|
||||
* @return true if is discovered
|
||||
*/
|
||||
public boolean isDiscovered(V vertex) throws NullPointerException {
|
||||
try {
|
||||
return discovered.containsKey(vertex);
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the vertex is visited or not
|
||||
*
|
||||
* @param vertex the vertex chosen
|
||||
* @return true if is visited
|
||||
*/
|
||||
public boolean isVisited(V vertex) throws NullPointerException {
|
||||
try {
|
||||
return visited.containsKey(vertex);
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a vertex as "visited". After this call the vertex is set as discovered (if not already) and visited.<br>
|
||||
* Next this call it will be possible to get the time of visit of that vertex<br>
|
||||
* Does nothing if the vertex is already been visited.
|
||||
*
|
||||
* @param vertex the vertex that has been visited
|
||||
*/
|
||||
synchronized void setVisited(V vertex) {
|
||||
setDiscovered(vertex);
|
||||
if (!visited.containsKey(vertex))
|
||||
visited.put(vertex, time++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a vertex as "discovered". After this call the vertex is set as discovered and it will be possible to get the time of it's discovery<br>
|
||||
* Does nothing if the vertex is already been discovered.
|
||||
*
|
||||
* @param vertex the vertex that has been discovered
|
||||
*/
|
||||
synchronized void setDiscovered(V vertex) {
|
||||
if (!discovered.containsKey(vertex))
|
||||
discovered.put(vertex, time++);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent of a particular vertex<br>
|
||||
* The parent of a vertex is the one that has discovered it<br>
|
||||
* If the target vertex is not already discovered, then {@link #setDiscovered(Object)} is called<br>
|
||||
*
|
||||
* @param parent the vertex that is the parent
|
||||
* @param child the vertex discovered
|
||||
* @throws IllegalArgumentException if the parent is not already discovered
|
||||
*/
|
||||
synchronized void setParent(V parent, V child) throws IllegalArgumentException {
|
||||
if (!isDiscovered(parent))
|
||||
throw new IllegalArgumentException(parent.toString());
|
||||
|
||||
setDiscovered(child);
|
||||
this.parent.putIfAbsent(child, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source of the visit.
|
||||
*
|
||||
@@ -157,13 +51,148 @@ public class VisitInfo<V> {
|
||||
*
|
||||
* @param vertex the child vertex
|
||||
* @return the parent of the child
|
||||
* @throws IllegalArgumentException if the vertex has not been discovered yet
|
||||
* @throws IllegalArgumentException if the vertex has not been discovered yet or is null
|
||||
*/
|
||||
public V getParentOf(V vertex) throws IllegalArgumentException {
|
||||
if (isDiscovered(vertex))
|
||||
return parent.get(vertex);
|
||||
VertexInfo info = vertices.get(vertex);
|
||||
if (!isDiscovered(vertex))
|
||||
throw new IllegalArgumentException();
|
||||
return info.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The time of the vertex when it is discovered in the visit.<br>
|
||||
* For "discovered" i mean when the node is first found by the visit algorithm. It may depends form {@link VisitStrategy}<br>
|
||||
* The time starts at 0 and for each vertex discovered it is increased by one. If a vertex is visited it also increase the time<br>
|
||||
*
|
||||
* @param vertex the vertex needed
|
||||
* @return the time of it's discovery
|
||||
* @throws IllegalArgumentException if the vertex is not discovered
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
public long getTimeDiscover(V vertex) throws IllegalArgumentException, NullPointerException {
|
||||
VertexInfo info = vertices.get(vertex);
|
||||
long time = (info == null) ? NOT_SET : info.timeDiscovered;
|
||||
|
||||
if(time == NOT_SET)
|
||||
throw new IllegalArgumentException();
|
||||
return time;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException();
|
||||
/**
|
||||
* The time when the vertex is visited by the algorithm<br>
|
||||
* For "visited" i mean when the node is finally visited by the visit algorithm. It may depends form {@link VisitStrategy}<br>
|
||||
* The time starts at 0 and for each vertex discovered or visited is increased by one<br>
|
||||
*
|
||||
* @param vertex the vertex needed
|
||||
* @return the time of it's visit
|
||||
* @throws IllegalArgumentException if the vertex is not visited
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
public long getTimeVisit(V vertex) throws IllegalArgumentException, NullPointerException {
|
||||
VertexInfo info = vertices.get(vertex);
|
||||
long time = (info == null) ? NOT_SET : info.timeVisited;
|
||||
|
||||
if(time == NOT_SET)
|
||||
throw new IllegalArgumentException();
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* The depth of the vertex when it was first discovered.
|
||||
*
|
||||
* @param vertex the vertex needed
|
||||
* @return the depth of it's discovery
|
||||
* @throws IllegalArgumentException if the vertex is not discovered
|
||||
* @throws NullPointerException if the vertex is null
|
||||
*/
|
||||
public long getDepth(V vertex) throws IllegalArgumentException, NullPointerException {
|
||||
VertexInfo info = vertices.get(vertex);
|
||||
long depth = (info == null) ? NOT_SET : info.depth;
|
||||
|
||||
if(depth == NOT_SET)
|
||||
throw new IllegalArgumentException();
|
||||
return depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if a vertex is discovered or not
|
||||
*
|
||||
* @param vertex the vertex chosen
|
||||
* @return true if is discovered
|
||||
*/
|
||||
public boolean isDiscovered(V vertex) throws NullPointerException {
|
||||
try {
|
||||
return vertices.get(vertex).timeDiscovered != NOT_SET;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the vertex is visited or not
|
||||
*
|
||||
* @param vertex the vertex chosen
|
||||
* @return true if is visited
|
||||
*/
|
||||
public boolean isVisited(V vertex) throws NullPointerException {
|
||||
try {
|
||||
return vertices.get(vertex).timeVisited != NOT_SET;
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a vertex as "visited". After this call the vertex is set as discovered (if not already) and visited.<br>
|
||||
* Next this call it will be possible to get the time of visit of that vertex<br>
|
||||
* Does nothing if the vertex has already been visited.
|
||||
*
|
||||
* @param vertex the vertex that has been visited
|
||||
*/
|
||||
synchronized void setVisited(V vertex) {
|
||||
setDiscovered(vertex);
|
||||
VertexInfo info = vertices.get(vertex);
|
||||
if(info.timeVisited != NOT_SET)
|
||||
return;
|
||||
|
||||
info.timeVisited = time;
|
||||
time++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a vertex as "discovered". After this call the vertex is set as discovered and it will be possible to get the time of it's discovery<br>
|
||||
* Does nothing if the vertex has already been discovered.
|
||||
*
|
||||
* @param vertex the vertex that has been discovered
|
||||
*/
|
||||
synchronized void setDiscovered(V vertex) {
|
||||
VertexInfo info = vertices.computeIfAbsent(vertex, (v) -> new VertexInfo(vertex));
|
||||
if(info.timeDiscovered != NOT_SET)
|
||||
return;
|
||||
|
||||
info.timeDiscovered = time;
|
||||
info.depth = 0;
|
||||
time++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent of a particular vertex<br>
|
||||
* The parent of a vertex is the one that has discovered it<br>
|
||||
* If the target vertex is not already discovered, then {@link #setDiscovered(Object)} is called<br>
|
||||
*
|
||||
* @param parent the vertex that is the parent
|
||||
* @param child the vertex discovered
|
||||
* @throws IllegalArgumentException if the parent is not already discovered
|
||||
*/
|
||||
synchronized void setParent(V parent, V child) throws IllegalArgumentException {
|
||||
if (!isDiscovered(parent))
|
||||
throw new IllegalArgumentException(parent.toString());
|
||||
|
||||
setDiscovered(child);
|
||||
VertexInfo info = vertices.get(child);
|
||||
info.parent = parent;
|
||||
info.depth = vertices.get(parent).depth + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,7 +201,12 @@ public class VisitInfo<V> {
|
||||
* @return the visited vertices
|
||||
*/
|
||||
public Set<V> getVisited() {
|
||||
return visited.keySet();
|
||||
Set<V> visited = new HashSet<>(vertices.size());
|
||||
vertices.forEach((vert, info) -> {
|
||||
if(info.timeVisited != NOT_SET)
|
||||
visited.add(vert);
|
||||
});
|
||||
return visited;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +215,12 @@ public class VisitInfo<V> {
|
||||
* @return the discovered vertices
|
||||
*/
|
||||
public Set<V> getDiscovered() {
|
||||
return discovered.keySet();
|
||||
Set<V> discovered = new HashSet<>(vertices.size());
|
||||
vertices.forEach((vert, info) -> {
|
||||
if(info.timeDiscovered != NOT_SET)
|
||||
discovered.add(vert);
|
||||
});
|
||||
return discovered;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,10 +230,11 @@ public class VisitInfo<V> {
|
||||
* @param consumer the function to apply to each
|
||||
*/
|
||||
public void forEachDiscovered(Consumer<VertexInfo> consumer) {
|
||||
Set<V> vertices = getDiscovered();
|
||||
Queue<VertexInfo> queue = new PriorityQueue<>();
|
||||
|
||||
vertices.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), isVisited(vertex) ? getTimeVisit(vertex) : -1, false)));
|
||||
vertices.forEach((v, info) -> {
|
||||
if(info.timeDiscovered != NOT_SET)
|
||||
queue.offer(new VertexInfo(info, false));
|
||||
});
|
||||
|
||||
while (!queue.isEmpty())
|
||||
consumer.accept(queue.poll());
|
||||
@@ -207,10 +247,11 @@ public class VisitInfo<V> {
|
||||
* @param consumer the function to apply to each
|
||||
*/
|
||||
public void forEachVisited(Consumer<VertexInfo> consumer) {
|
||||
Set<V> vertices = getVisited();
|
||||
Queue<VertexInfo> queue = new PriorityQueue<>();
|
||||
|
||||
vertices.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), getTimeVisit(vertex), true)));
|
||||
vertices.forEach((v, info) -> {
|
||||
if(info.timeVisited != NOT_SET)
|
||||
queue.offer(new VertexInfo(info, true));
|
||||
});
|
||||
|
||||
while (!queue.isEmpty())
|
||||
consumer.accept(queue.poll());
|
||||
@@ -223,46 +264,70 @@ public class VisitInfo<V> {
|
||||
* @param consumer the function to apply at each vertex
|
||||
*/
|
||||
public void forEach(Consumer<VertexInfo> consumer) {
|
||||
Set<V> discovered = getDiscovered();
|
||||
Set<V> visited = getVisited();
|
||||
Queue<VertexInfo> queue = new PriorityQueue<>();
|
||||
|
||||
discovered.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), getTimeVisit(vertex), false)));
|
||||
visited.forEach((vertex) -> queue.offer(new VertexInfo(vertex, getParentOf(vertex), getTimeDiscover(vertex), getTimeVisit(vertex), true)));
|
||||
|
||||
vertices.forEach((v, info) -> {
|
||||
if(info.timeDiscovered != NOT_SET)
|
||||
queue.offer(new VertexInfo(info, false));
|
||||
if(info.timeVisited != NOT_SET)
|
||||
queue.offer(new VertexInfo(info, true));
|
||||
});
|
||||
|
||||
while (!queue.isEmpty())
|
||||
consumer.accept(queue.remove());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Class used mainly for storing the data of the visit
|
||||
*/
|
||||
public class VertexInfo implements Comparable<VertexInfo> {
|
||||
public final V vertex;
|
||||
public final V parent;
|
||||
public final long timeDiscovered;
|
||||
public final long timeVisited;
|
||||
public V vertex;
|
||||
public V parent;
|
||||
public long timeDiscovered;
|
||||
public long timeVisited;
|
||||
public long depth;
|
||||
private final boolean compareVisited;
|
||||
|
||||
private VertexInfo(V vertex, V parent, long timeDiscovered, long timeVisited, boolean compareVisited) {
|
||||
this.vertex = vertex;
|
||||
this.parent = parent;
|
||||
this.timeDiscovered = timeDiscovered;
|
||||
this.timeVisited = timeVisited;
|
||||
this.compareVisited = compareVisited;
|
||||
private VertexInfo(V vertex) {
|
||||
this.vertex = vertex;
|
||||
this.timeDiscovered = NOT_SET;
|
||||
this.timeVisited = NOT_SET;
|
||||
this.depth = NOT_SET;
|
||||
this.compareVisited = false;
|
||||
}
|
||||
|
||||
private VertexInfo(VertexInfo info, boolean compare) {
|
||||
this.vertex = info.vertex;
|
||||
this.parent = info.parent;
|
||||
this.timeDiscovered = info.timeDiscovered;
|
||||
this.timeVisited = info.timeVisited;
|
||||
this.depth = info.depth;
|
||||
this.compareVisited = compare;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
try {
|
||||
return obj instanceof VisitInfo.VertexInfo && obj.toString().equals(toString());
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(VertexInfo other) {
|
||||
long compareThis = compareVisited ? timeVisited : timeDiscovered;
|
||||
long compareOther = other.compareVisited ? other.timeVisited : other.timeDiscovered;
|
||||
|
||||
return (int) (compareThis - compareOther);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s -> %s [D:%3d, V:%3d]", parent, vertex, timeDiscovered, timeVisited);
|
||||
return String.format("%s -> %s (%3d) [D:%3d, V:%3d]", parent, vertex, depth, timeDiscovered, timeVisited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,31 @@
|
||||
package berack96.test.lib;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.Vertex;
|
||||
import berack96.lib.graph.models.GraphSaveStructure;
|
||||
import berack96.lib.graph.visit.impl.BFS;
|
||||
import berack96.lib.graph.visit.impl.DFS;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Timeout;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
import berack96.lib.graph.Edge;
|
||||
import berack96.lib.graph.Graph;
|
||||
import berack96.lib.graph.Vertex;
|
||||
import berack96.lib.graph.impl.AdjGraph;
|
||||
import berack96.lib.graph.impl.MapGraph;
|
||||
import berack96.lib.graph.impl.MatrixGraph;
|
||||
import berack96.lib.graph.visit.impl.BFS;
|
||||
import berack96.lib.graph.visit.impl.DFS;
|
||||
import berack96.lib.graph.visit.impl.VisitInfo;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Timeout(value = 2)
|
||||
public class TestGraph {
|
||||
|
||||
/* We only try this for sake of simplicity */
|
||||
/* I decided to only try this for sake of simplicity */
|
||||
private Graph<String, Integer> graph;
|
||||
|
||||
private final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
@@ -48,17 +33,16 @@ public class TestGraph {
|
||||
private final String encoding = "UTF-8";
|
||||
private final Exception nullException = new NullPointerException(Graph.PARAM_NULL);
|
||||
private final Exception notException = new IllegalArgumentException(Graph.VERTEX_NOT_CONTAINED);
|
||||
private final Exception unsuppException = new UnsupportedOperationException(Vertex.REMOVED);
|
||||
private final Exception unSuppException = new UnsupportedOperationException(Vertex.REMOVED);
|
||||
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
// Change here the instance for changing all the test for that particular class
|
||||
graph = new MapGraph<>();
|
||||
// graph = new MatrixGraph<>();
|
||||
// graph = new AdjGraph<>();
|
||||
//graph = new berack96.lib.graph.impl.MapGraph<>();
|
||||
//graph = new berack96.lib.graph.impl.MatrixGraph<>();
|
||||
graph = new berack96.lib.graph.impl.ListGraph<>();
|
||||
|
||||
PrintStream p = null;
|
||||
PrintStream p;
|
||||
try {
|
||||
p = new PrintStream(bytes, true, encoding);
|
||||
System.setErr(p);
|
||||
@@ -68,7 +52,7 @@ public class TestGraph {
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
@AfterEach
|
||||
public void after() {
|
||||
try {
|
||||
String printed = bytes.toString(encoding);
|
||||
@@ -82,48 +66,48 @@ public class TestGraph {
|
||||
|
||||
@Test
|
||||
public void basicVertex() {
|
||||
assertEquals(0, graph.numberOfVertices());
|
||||
assertEquals(0, graph.size());
|
||||
|
||||
graph.addVertex("1");
|
||||
graph.addVertex("2");
|
||||
shouldThrow(nullException, () -> graph.addVertex(null));
|
||||
graph.add("1");
|
||||
graph.add("2");
|
||||
shouldThrow(nullException, () -> graph.add(null));
|
||||
|
||||
assertTrue(graph.contains("1"));
|
||||
assertFalse(graph.contains("0"));
|
||||
assertTrue(graph.contains("2"));
|
||||
assertFalse(graph.contains("3"));
|
||||
assertEquals(2, graph.numberOfVertices());
|
||||
assertEquals(2, graph.size());
|
||||
|
||||
graph.removeVertex("1");
|
||||
graph.remove("1");
|
||||
assertFalse(graph.contains("1"));
|
||||
assertTrue(graph.contains("2"));
|
||||
assertEquals(1, graph.numberOfVertices());
|
||||
assertEquals(1, graph.size());
|
||||
|
||||
graph.addVertex("3");
|
||||
graph.add("3");
|
||||
assertTrue(graph.contains("3"));
|
||||
shouldThrow(nullException, () -> graph.contains(null));
|
||||
shouldThrow(nullException, () -> graph.addVertexIfAbsent(null));
|
||||
shouldThrow(nullException, () -> graph.addIfAbsent(null));
|
||||
|
||||
assertTrue(graph.addVertexIfAbsent("4"));
|
||||
assertFalse(graph.addVertexIfAbsent("4"));
|
||||
assertFalse(graph.addVertexIfAbsent("2"));
|
||||
assertTrue(graph.addIfAbsent("4"));
|
||||
assertFalse(graph.addIfAbsent("4"));
|
||||
assertFalse(graph.addIfAbsent("2"));
|
||||
|
||||
assertEquals(3, graph.numberOfVertices());
|
||||
assertEquals(3, graph.size());
|
||||
shouldContain(graph.vertices(), "2", "3", "4");
|
||||
|
||||
graph.removeAllVertex();
|
||||
graph.removeAll();
|
||||
shouldContain(graph.vertices());
|
||||
|
||||
Set<String> vertices = new HashSet<>(Arrays.asList("1", "5", "24", "2", "3"));
|
||||
graph.addAllVertices(vertices);
|
||||
graph.addAll(vertices);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
graph.removeVertex("1");
|
||||
graph.removeVertex("24");
|
||||
graph.remove("1");
|
||||
graph.remove("24");
|
||||
shouldContain(graph.vertices(), "5", "2", "3");
|
||||
graph.addAllVertices(vertices);
|
||||
graph.addAll(vertices);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
|
||||
shouldThrow(nullException, () -> graph.addAllVertices(null));
|
||||
shouldThrow(nullException, () -> graph.addAll(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -136,16 +120,16 @@ public class TestGraph {
|
||||
* v v
|
||||
* 3 <-> 5 -> 4
|
||||
*/
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
|
||||
shouldThrow(nullException, () -> graph.addEdge(null, "2", 1));
|
||||
shouldThrow(nullException, () -> graph.addEdge(null, null, 1));
|
||||
shouldThrow(nullException, () -> graph.addEdge("1", null, 1));
|
||||
shouldThrow(new NullPointerException(), () -> graph.addEdge(null));
|
||||
shouldThrow(nullException, () -> graph.addEdge(null));
|
||||
shouldThrow(nullException, () -> graph.addEdge(new Edge<>("1", null, 1)));
|
||||
shouldThrow(nullException, () -> graph.addEdge(new Edge<>(null, null, 1)));
|
||||
shouldThrow(nullException, () -> graph.addEdge(new Edge<>(null, "2", 1)));
|
||||
@@ -193,21 +177,21 @@ public class TestGraph {
|
||||
|
||||
assertEquals(6, graph.numberOfEdges());
|
||||
|
||||
assertEquals(new Integer(1), graph.getWeight("1", "2"));
|
||||
assertEquals(new Integer(1), graph.getWeight("1", "3"));
|
||||
assertEquals(new Integer(4), graph.getWeight("2", "5"));
|
||||
assertEquals(new Integer(2), graph.getWeight("3", "5"));
|
||||
assertEquals(new Integer(2), graph.getWeight("5", "3"));
|
||||
assertEquals(new Integer(3), graph.getWeight("5", "4"));
|
||||
assertEquals(Integer.valueOf(1), graph.getWeight("1", "2"));
|
||||
assertEquals(Integer.valueOf(1), graph.getWeight("1", "3"));
|
||||
assertEquals(Integer.valueOf(4), graph.getWeight("2", "5"));
|
||||
assertEquals(Integer.valueOf(2), graph.getWeight("3", "5"));
|
||||
assertEquals(Integer.valueOf(2), graph.getWeight("5", "3"));
|
||||
assertEquals(Integer.valueOf(3), graph.getWeight("5", "4"));
|
||||
|
||||
assertNull(graph.getWeight("1", "4"));
|
||||
|
||||
assertEquals(new Integer(1), graph.addEdge("1", "2", 102));
|
||||
assertEquals(new Integer(102), graph.addEdge("1", "2", 3));
|
||||
assertEquals(new Integer(3), graph.addEdge("1", "2", 1));
|
||||
assertEquals(new Integer(1), graph.addEdge(new Edge<>("1", "2", 102)));
|
||||
assertEquals(new Integer(102), graph.addEdge(new Edge<>("1", "2", 3)));
|
||||
assertEquals(new Integer(3), graph.addEdge(new Edge<>("1", "2", 1)));
|
||||
assertEquals(Integer.valueOf(1), graph.addEdge("1", "2", 102));
|
||||
assertEquals(Integer.valueOf(102), graph.addEdge("1", "2", 3));
|
||||
assertEquals(Integer.valueOf(3), graph.addEdge("1", "2", 1));
|
||||
assertEquals(Integer.valueOf(1), graph.addEdge(new Edge<>("1", "2", 102)));
|
||||
assertEquals(Integer.valueOf(102), graph.addEdge(new Edge<>("1", "2", 3)));
|
||||
assertEquals(Integer.valueOf(3), graph.addEdge(new Edge<>("1", "2", 1)));
|
||||
|
||||
assertEquals(6, graph.numberOfEdges());
|
||||
assertTrue(graph.containsEdge("1", "2"));
|
||||
@@ -298,10 +282,10 @@ public class TestGraph {
|
||||
assertEquals(35, graph.addEdgeAndVertices(new Edge<>("2aa", "323", 5)).intValue());
|
||||
assertEquals(50, graph.addEdgeAndVertices(new Edge<>("2", "323", 500)).intValue());
|
||||
|
||||
graph.removeAllVertex();
|
||||
graph.addVertex("aaa");
|
||||
graph.addVertex("1");
|
||||
graph.addVertex("2");
|
||||
graph.removeAll();
|
||||
graph.add("aaa");
|
||||
graph.add("1");
|
||||
graph.add("2");
|
||||
|
||||
shouldContain(graph.vertices(), "1", "2", "aaa");
|
||||
shouldContain(graph.edges());
|
||||
@@ -333,12 +317,12 @@ public class TestGraph {
|
||||
* 3 <-> 5 -> 4
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
|
||||
shouldContain(graph.edges());
|
||||
|
||||
@@ -351,12 +335,12 @@ public class TestGraph {
|
||||
graph.addEdge("5", "3", 9);
|
||||
graph.addEdge("5", "4", 5);
|
||||
|
||||
shouldContain(graph.getChildren("1"), "2", "3");
|
||||
shouldContain(graph.getChildren("2"), "5", "6");
|
||||
shouldContain(graph.getChildren("3"), "5");
|
||||
shouldContain(graph.getChildren("4"), "6");
|
||||
shouldContain(graph.getChildren("5"), "3", "4");
|
||||
shouldContain(graph.getChildren("6"));
|
||||
shouldContain(graph.getChildrens("1"), "2", "3");
|
||||
shouldContain(graph.getChildrens("2"), "5", "6");
|
||||
shouldContain(graph.getChildrens("3"), "5");
|
||||
shouldContain(graph.getChildrens("4"), "6");
|
||||
shouldContain(graph.getChildrens("5"), "3", "4");
|
||||
shouldContain(graph.getChildrens("6"));
|
||||
|
||||
shouldContain(graph.getAncestors("1"));
|
||||
shouldContain(graph.getAncestors("2"), "1");
|
||||
@@ -417,6 +401,25 @@ public class TestGraph {
|
||||
new Edge<>("3", "5", 2),
|
||||
new Edge<>("5", "3", 9),
|
||||
new Edge<>("5", "4", 5));
|
||||
|
||||
/* Weird case in the add */
|
||||
graph.addIfAbsent("2");
|
||||
shouldContain(graph.edges(),
|
||||
new Edge<>("1", "2", 1),
|
||||
new Edge<>("1", "3", 1),
|
||||
new Edge<>("2", "5", 4),
|
||||
new Edge<>("2", "6", 5),
|
||||
new Edge<>("3", "5", 2),
|
||||
new Edge<>("4", "6", 6),
|
||||
new Edge<>("5", "3", 9),
|
||||
new Edge<>("5", "4", 5));
|
||||
graph.add("2");
|
||||
shouldContain(graph.edges(),
|
||||
new Edge<>("1", "3", 1),
|
||||
new Edge<>("3", "5", 2),
|
||||
new Edge<>("4", "6", 6),
|
||||
new Edge<>("5", "3", 9),
|
||||
new Edge<>("5", "4", 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -424,8 +427,9 @@ public class TestGraph {
|
||||
VisitInfo<Integer> info = new VisitInfo<>(0);
|
||||
assertTrue(info.isDiscovered(0));
|
||||
assertFalse(info.isVisited(0));
|
||||
assertEquals(0, info.getDepth(0));
|
||||
assertEquals(0, info.getTimeDiscover(0));
|
||||
assertEquals(new Integer(0), info.getSource());
|
||||
assertEquals(Integer.valueOf(0), info.getSource());
|
||||
assertNull(info.getParentOf(0));
|
||||
|
||||
assertFalse(info.isVisited(null));
|
||||
@@ -434,10 +438,12 @@ public class TestGraph {
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getTimeVisit(0));
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getTimeDiscover(1));
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getParentOf(2));
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getParentOf(null));
|
||||
shouldThrow(new IllegalArgumentException(), () -> info.getDepth(2));
|
||||
|
||||
shouldThrow(new NullPointerException(), () -> info.getTimeDiscover(null));
|
||||
shouldThrow(new NullPointerException(), () -> info.getTimeVisit(null));
|
||||
shouldThrow(new NullPointerException(), () -> info.getParentOf(null));
|
||||
shouldThrow(new NullPointerException(), () -> info.getDepth(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -452,14 +458,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -503,6 +509,7 @@ public class TestGraph {
|
||||
assertEquals(verticesDiscovered[integer.get()], vertexInfo.vertex);
|
||||
integer.incrementAndGet();
|
||||
});
|
||||
|
||||
integer.set(0);
|
||||
int[] visitTime = {4, 7, 8, 9, 10, 11};
|
||||
String[] verticesVisited = {"3", "6", "4", "5", "2", "1"};
|
||||
@@ -511,6 +518,24 @@ public class TestGraph {
|
||||
assertEquals(verticesVisited[integer.get()], vertexInfo.vertex);
|
||||
integer.incrementAndGet();
|
||||
});
|
||||
|
||||
String[] vertices = {"1", "2", "5", "3", "3", "4", "6", "6", "4", "5", "2", "1"};
|
||||
boolean[] found = new boolean[graph.size()];
|
||||
integer.set(0);
|
||||
visitDFS.forEach(vertexInfo -> {
|
||||
int i = integer.get();
|
||||
assertEquals(vertices[i], vertexInfo.vertex, "Iter " + i);
|
||||
int vert = Integer.parseInt(vertexInfo.vertex);
|
||||
|
||||
if(found[vert])
|
||||
assertEquals(i, vertexInfo.timeVisited, "Iter " + i);
|
||||
else {
|
||||
assertEquals(i, vertexInfo.timeDiscovered, "Iter " + i);
|
||||
found[vert] = true;
|
||||
}
|
||||
|
||||
integer.incrementAndGet();
|
||||
});
|
||||
|
||||
BFS<String, Integer> bfs = new BFS<>();
|
||||
VisitInfo<String> visitBFS = graph.visit("1", bfs, null);
|
||||
@@ -542,14 +567,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -564,7 +589,7 @@ public class TestGraph {
|
||||
Set<String> vertices = new HashSet<>();
|
||||
|
||||
Iterator<String> iter = graph.iterator();
|
||||
assertTrue("This should not be null!", iter != null);
|
||||
assertNotNull(iter, "This should not be null!");
|
||||
while (iter.hasNext())
|
||||
vertices.add(iter.next());
|
||||
shouldContain(vertices, "1", "2", "3", "4", "5", "6", "7", "8");
|
||||
@@ -591,12 +616,12 @@ public class TestGraph {
|
||||
* 3 <-> 5 -> 4
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -619,14 +644,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
before();
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -656,12 +681,12 @@ public class TestGraph {
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
@@ -687,12 +712,12 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4
|
||||
*/
|
||||
before();
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
|
||||
assertFalse(graph.isCyclic());
|
||||
assertTrue(graph.isDAG());
|
||||
@@ -733,14 +758,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -752,7 +777,7 @@ public class TestGraph {
|
||||
graph.addEdge("7", "8", 8);
|
||||
|
||||
Graph<String, Integer> transposed = graph.transpose();
|
||||
assertTrue("This should not be null!", transposed != null);
|
||||
assertNotNull(transposed, "This should not be null!");
|
||||
|
||||
DFS<String, Integer> dfs = new DFS<>();
|
||||
VisitInfo<String> visitDFS = transposed.visit("6", dfs, null);
|
||||
@@ -795,12 +820,12 @@ public class TestGraph {
|
||||
* 3 -> 5 -> 4
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -826,14 +851,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 10);
|
||||
@@ -845,7 +870,7 @@ public class TestGraph {
|
||||
graph.addEdge("7", "8", 8);
|
||||
|
||||
List<Edge<String, Integer>> distance = graph.distance("1", "6");
|
||||
assertTrue("This should not be null!", distance != null);
|
||||
assertNotNull(distance, "This should not be null!");
|
||||
int sum = distance.stream().mapToInt(Edge::getWeight).sum();
|
||||
assertEquals(13, sum);
|
||||
shouldContainInOrder(distance,
|
||||
@@ -885,14 +910,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 -> 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 10);
|
||||
@@ -905,7 +930,7 @@ public class TestGraph {
|
||||
graph.addEdge("7", "8", 8);
|
||||
|
||||
Map<String, List<Edge<String, Integer>>> distance = graph.distance("1");
|
||||
assertTrue("This should not be null!", distance != null);
|
||||
assertNotNull(distance, "This should not be null!");
|
||||
assertNull(distance.get("1"));
|
||||
shouldContainInOrder(distance.get("2"),
|
||||
new Edge<>("1", "2", 1));
|
||||
@@ -945,14 +970,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -1094,7 +1119,7 @@ public class TestGraph {
|
||||
@Test
|
||||
public void subGraph() {
|
||||
/*
|
||||
* This graph should be like this
|
||||
* This graph should look like this
|
||||
*
|
||||
* 1 -> 2 <- 6 7
|
||||
* ^ ^
|
||||
@@ -1103,14 +1128,14 @@ public class TestGraph {
|
||||
* 3 <- 5 -> 4 8
|
||||
*/
|
||||
|
||||
graph.addVertexIfAbsent("1");
|
||||
graph.addVertexIfAbsent("2");
|
||||
graph.addVertexIfAbsent("3");
|
||||
graph.addVertexIfAbsent("4");
|
||||
graph.addVertexIfAbsent("5");
|
||||
graph.addVertexIfAbsent("6");
|
||||
graph.addVertexIfAbsent("7");
|
||||
graph.addVertexIfAbsent("8");
|
||||
graph.addIfAbsent("1");
|
||||
graph.addIfAbsent("2");
|
||||
graph.addIfAbsent("3");
|
||||
graph.addIfAbsent("4");
|
||||
graph.addIfAbsent("5");
|
||||
graph.addIfAbsent("6");
|
||||
graph.addIfAbsent("7");
|
||||
graph.addIfAbsent("8");
|
||||
|
||||
graph.addEdge("1", "2", 1);
|
||||
graph.addEdge("1", "3", 1);
|
||||
@@ -1140,7 +1165,7 @@ public class TestGraph {
|
||||
graph.mark("4", "z");
|
||||
|
||||
Graph<String, Integer> sub = graph.subGraph("1", -541);
|
||||
assertTrue("This should not be null!", sub != null);
|
||||
assertNotNull(sub, "This should not be null!");
|
||||
shouldContain(sub.vertices(), "1");
|
||||
shouldContain(sub.edges());
|
||||
|
||||
@@ -1222,7 +1247,8 @@ public class TestGraph {
|
||||
sub = graph.subGraph();
|
||||
shouldContain(sub.vertices(), "7", "8");
|
||||
shouldContain(sub.edges(), new Edge<>("8", "7", 9));
|
||||
|
||||
|
||||
//noinspection ConfusingArgumentToVarargsMethod
|
||||
sub = graph.subGraph(null);
|
||||
shouldContain(sub.vertices(), "7", "8");
|
||||
shouldContain(sub.edges(), new Edge<>("8", "7", 9));
|
||||
@@ -1233,31 +1259,31 @@ public class TestGraph {
|
||||
Vertex<String> vertex = new Vertex<>(graph, "stronzo");
|
||||
|
||||
assertEquals("stronzo", vertex.getValue());
|
||||
assertEquals(0, graph.numberOfVertices());
|
||||
assertEquals(0, graph.size());
|
||||
|
||||
shouldThrow(unsuppException, () -> vertex.addChild(null, null));
|
||||
shouldThrow(unsuppException, () -> vertex.mark(null));
|
||||
shouldThrow(unsuppException, () -> vertex.removeChild(null));
|
||||
shouldThrow(unsuppException, () -> vertex.visit(null, null));
|
||||
shouldThrow(unsuppException, vertex::unMark);
|
||||
shouldThrow(unsuppException, vertex::getAncestors);
|
||||
shouldThrow(unsuppException, vertex::getChildren);
|
||||
shouldThrow(unsuppException, vertex::getEdgesOut);
|
||||
shouldThrow(unsuppException, vertex::getEdgesIn);
|
||||
shouldThrow(unsuppException, vertex::getChildrenAsVertex);
|
||||
shouldThrow(unsuppException, vertex::getAncestorsAsVertex);
|
||||
shouldThrow(unsuppException, vertex::getMarks);
|
||||
shouldThrow(unSuppException, () -> vertex.addChild(null, null));
|
||||
shouldThrow(unSuppException, () -> vertex.mark(null));
|
||||
shouldThrow(unSuppException, () -> vertex.removeChild(null));
|
||||
shouldThrow(unSuppException, () -> vertex.visit(null, null));
|
||||
shouldThrow(unSuppException, vertex::unMark);
|
||||
shouldThrow(unSuppException, vertex::getAncestors);
|
||||
shouldThrow(unSuppException, vertex::getChildren);
|
||||
shouldThrow(unSuppException, vertex::getEdgesOut);
|
||||
shouldThrow(unSuppException, vertex::getEdgesIn);
|
||||
shouldThrow(unSuppException, vertex::getChildrenAsVertex);
|
||||
shouldThrow(unSuppException, vertex::getAncestorsAsVertex);
|
||||
shouldThrow(unSuppException, vertex::getMarks);
|
||||
|
||||
vertex.addIfAbsent();
|
||||
assertEquals(1, graph.numberOfVertices());
|
||||
assertEquals(1, graph.size());
|
||||
vertex.addIfAbsent();
|
||||
assertEquals(1, graph.numberOfVertices());
|
||||
assertEquals(1, graph.size());
|
||||
vertex.addIfAbsent();
|
||||
assertEquals(1, graph.numberOfVertices());
|
||||
assertEquals(1, graph.size());
|
||||
|
||||
assertEquals(vertex, graph.getVertex("stronzo"));
|
||||
shouldThrow(nullException, () -> graph.getVertex(null));
|
||||
shouldThrow(notException, () -> graph.getVertex("stronzo1"));
|
||||
assertEquals(vertex, graph.get("stronzo"));
|
||||
shouldThrow(nullException, () -> graph.get(null));
|
||||
shouldThrow(notException, () -> graph.get("stronzo1"));
|
||||
|
||||
shouldThrow(nullException, () -> vertex.addChild(null, 3));
|
||||
shouldThrow(nullException, () -> vertex.addChild(null, null));
|
||||
@@ -1277,9 +1303,9 @@ public class TestGraph {
|
||||
shouldContain(vertex.getEdgesIn());
|
||||
shouldContain(vertex.getEdgesOut());
|
||||
|
||||
graph.addVertex("1");
|
||||
graph.addVertex("2");
|
||||
graph.addVertex("3");
|
||||
graph.add("1");
|
||||
graph.add("2");
|
||||
graph.add("3");
|
||||
|
||||
graph.addEdge("1", "2", 2);
|
||||
graph.addEdge("3", "stronzo", 6);
|
||||
@@ -1330,23 +1356,23 @@ public class TestGraph {
|
||||
vertex.remove();
|
||||
assertFalse(vertex.isStillContained());
|
||||
assertFalse(graph.contains(vertex.getValue()));
|
||||
assertEquals(3, graph.numberOfVertices());
|
||||
assertEquals(3, graph.size());
|
||||
|
||||
shouldThrow(unsuppException, () -> vertex.addChild(null, null));
|
||||
shouldThrow(unsuppException, () -> vertex.mark(null));
|
||||
shouldThrow(unsuppException, () -> vertex.removeChild(null));
|
||||
shouldThrow(unsuppException, () -> vertex.visit(null, null));
|
||||
shouldThrow(unsuppException, vertex::unMark);
|
||||
shouldThrow(unsuppException, vertex::getAncestors);
|
||||
shouldThrow(unsuppException, vertex::getChildren);
|
||||
shouldThrow(unsuppException, vertex::getEdgesOut);
|
||||
shouldThrow(unsuppException, vertex::getEdgesIn);
|
||||
shouldThrow(unsuppException, vertex::getChildrenAsVertex);
|
||||
shouldThrow(unsuppException, vertex::getAncestorsAsVertex);
|
||||
shouldThrow(unsuppException, vertex::getMarks);
|
||||
shouldThrow(unSuppException, () -> vertex.addChild(null, null));
|
||||
shouldThrow(unSuppException, () -> vertex.mark(null));
|
||||
shouldThrow(unSuppException, () -> vertex.removeChild(null));
|
||||
shouldThrow(unSuppException, () -> vertex.visit(null, null));
|
||||
shouldThrow(unSuppException, vertex::unMark);
|
||||
shouldThrow(unSuppException, vertex::getAncestors);
|
||||
shouldThrow(unSuppException, vertex::getChildren);
|
||||
shouldThrow(unSuppException, vertex::getEdgesOut);
|
||||
shouldThrow(unSuppException, vertex::getEdgesIn);
|
||||
shouldThrow(unSuppException, vertex::getChildrenAsVertex);
|
||||
shouldThrow(unSuppException, vertex::getAncestorsAsVertex);
|
||||
shouldThrow(unSuppException, vertex::getMarks);
|
||||
|
||||
vertex.addIfAbsent();
|
||||
assertEquals(4, graph.numberOfVertices());
|
||||
assertEquals(4, graph.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1401,33 +1427,35 @@ public class TestGraph {
|
||||
marks.put("6", new HashSet<>(temp));
|
||||
temp.clear();
|
||||
|
||||
graph.addAllVertices(vertices);
|
||||
graph.addAll(vertices);
|
||||
graph.addAllEdges(edges);
|
||||
marks.forEach((v, m) -> m.forEach(mk -> graph.mark(v, mk)));
|
||||
GraphSaveStructure<String, Integer> struct = new GraphSaveStructure<>();
|
||||
|
||||
try {
|
||||
Graph.save(graph, fileName);
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
struct.save(graph, fileName);
|
||||
struct.load(graph, fileName, String.class, Integer.class);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
shouldContain(graph.edges(), edges.toArray());
|
||||
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
|
||||
|
||||
graph.removeAllVertex();
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
graph.removeAll();
|
||||
struct.load(graph, fileName, String.class, Integer.class);
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
shouldContain(graph.edges(), edges.toArray());
|
||||
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Graph.load(graph, "sadadafacensi", String.class, Integer.class);
|
||||
struct.load(graph, "sadadafacensi", String.class, Integer.class);
|
||||
fail("Should have been thrown IOException");
|
||||
} catch (Exception ignore) {
|
||||
if (!(ignore instanceof IOException))
|
||||
fail("Should have been thrown IOException " + ignore.getMessage());
|
||||
} catch (Exception e) {
|
||||
if (!(e instanceof IOException))
|
||||
fail("Should have been thrown IOException " + e.getMessage());
|
||||
}
|
||||
|
||||
shouldContain(graph.vertices(), vertices.toArray());
|
||||
@@ -1435,16 +1463,16 @@ public class TestGraph {
|
||||
//marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray()));
|
||||
|
||||
try {
|
||||
Graph.load(graph, fileName + ".fail", String.class, Integer.class);
|
||||
struct.load(graph, fileName + ".fail", String.class, Integer.class);
|
||||
fail("Should have been thrown JsonSyntaxException");
|
||||
} catch (Exception ignore) {
|
||||
if (!(ignore instanceof JsonSyntaxException))
|
||||
fail("Should have been thrown JsonSyntaxException " + ignore.getMessage());
|
||||
} catch (Exception e) {
|
||||
if (!(e instanceof JsonSyntaxException))
|
||||
fail("Should have been thrown JsonSyntaxException " + e.getMessage());
|
||||
}
|
||||
|
||||
graph = null;
|
||||
shouldThrow(new NullPointerException(), () -> { try {
|
||||
Graph.load(graph, fileName, String.class, Integer.class);
|
||||
struct.load(graph, fileName, String.class, Integer.class);
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
e.printStackTrace();
|
||||
@@ -1454,28 +1482,29 @@ public class TestGraph {
|
||||
|
||||
|
||||
private void shouldContain(Collection<?> actual, Object... expected) {
|
||||
assertTrue("You should pass me a collection!", actual != null);
|
||||
assertEquals("They have not the same number of elements\nActual: " + actual, expected.length, actual.size());
|
||||
assertNotNull(actual, "You should pass me a collection!");
|
||||
assertEquals(expected.length, actual.size(), "They have not the same number of elements\nActual: " + actual);
|
||||
|
||||
for (Object obj : expected)
|
||||
assertTrue("Not containing: [" + obj + "]\nBut has: " + actual, actual.contains(obj));
|
||||
assertTrue(actual.contains(obj), "Not containing: [" + obj + "]\nBut has: " + actual);
|
||||
}
|
||||
|
||||
private void shouldContainInOrder(List<?> actual, Object... expected) {
|
||||
assertTrue("You should pass me a list!", actual != null);
|
||||
assertEquals("They have not the same number of elements\nActual: " + actual, expected.length, actual.size());
|
||||
assertNotNull(actual, "You should pass me a list!");
|
||||
assertEquals(expected.length, actual.size(), "They have not the same number of elements\nActual: " + actual);
|
||||
|
||||
for (int i = 0; i < actual.size(); i++)
|
||||
assertEquals("Index: " + i, expected[i], actual.get(i));
|
||||
assertEquals(expected[i], actual.get(i), "Index: " + i);
|
||||
}
|
||||
|
||||
private void shouldThrow(Exception expected, Runnable runnable) {
|
||||
try {
|
||||
runnable.run();
|
||||
fail("It has't thrown: " + expected.getClass().getSimpleName());
|
||||
fail("It hasn't thrown: " + expected.getClass().getSimpleName());
|
||||
} catch (Exception actual) {
|
||||
assertEquals(expected.getClass(), actual.getClass());
|
||||
assertEquals(expected.getMessage(), actual.getMessage());
|
||||
if(expected.getMessage()!=null)
|
||||
assertEquals(expected.getMessage(), actual.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","\"6\"","\"7\"","\"8\""],"edges":[{"src":"\"1\"","dest":"\"2\"","weight":"1"},{"src":"\"1\"","dest":"\"3\"","weight":"1"},{"src":"\"5\"","dest":"\"4\"","weight":"5"},{"src":"\"6\"","dest":"\"2\"","weight":"2"},{"src":"\"5\"","dest":"\"3\"","weight":"2"},{"src":"\"8\"","dest":"\"7\"","weight":"9"},{"src":"\"4\"","dest":"\"6\"","weight":"6"},{"src":"\"2\"","dest":"\"5\"","weight":"4"}],"other":""}
|
||||
{"gson":{"calls":{"threadLocalHashCode":865977613},"typeTokenCache":{"com.google.gson.reflect.TypeToken\u003c?\u003e":{},"com.google.gson.InstanceCreator\u003c?\u003e":{},"java.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.TypeAdapter\u003c?\u003e\u003e":{},"java.lang.Class\u003c?\u003e":{},"com.google.gson.internal.reflect.ReflectionAccessor":{},"com.google.gson.internal.ConstructorConstructor":{},"java.util.List\u003ccom.google.gson.ExclusionStrategy\u003e":{},"com.google.gson.internal.Excluder":{},"java.util.Map\u003cjava.lang.reflect.Type, com.google.gson.InstanceCreator\u003c?\u003e\u003e":{},"com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory":{},"berack96.lib.graph.models.EdgeSaveStructure":{},"berack96.lib.graph.models.EdgeSaveStructure[]":{},"java.util.List\u003ccom.google.gson.TypeAdapterFactory\u003e":{},"com.google.gson.FieldNamingStrategy":{},"com.google.gson.Gson":{},"double":{},"java.lang.String":{},"java.lang.String[]":{},"java.lang.reflect.Type":{},"int":{},"com.google.gson.ExclusionStrategy":{},"com.google.gson.TypeAdapter\u003c?\u003e":{},"java.lang.Integer":{},"com.google.gson.TypeAdapterFactory":{},"java.lang.ThreadLocal\u003cjava.util.Map\u003ccom.google.gson.reflect.TypeToken\u003c?\u003e, com.google.gson.Gson$FutureTypeAdapter\u003c?\u003e\u003e\u003e":{},"boolean":{},"com.google.gson.LongSerializationPolicy":{},"berack96.lib.graph.models.GraphSaveStructure":{}},"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}},"jsonAdapterFactory":{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},"factories":[null,null,{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}},"complexMapKeySerialization":false},{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},null,{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}},"fieldNamingPolicy":"IDENTITY","excluder":{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},"jsonAdapterFactory":{"constructorConstructor":{"instanceCreators":{},"accessor":{"theUnsafe":{}}}},"accessor":{"theUnsafe":{}}}],"excluder":{"version":-1.0,"modifiers":136,"serializeInnerClasses":true,"requireExpose":false,"serializationStrategies":[],"deserializationStrategies":[]},"fieldNamingStrategy":"IDENTITY","instanceCreators":{},"serializeNulls":false,"complexMapKeySerialization":false,"generateNonExecutableJson":false,"htmlSafe":true,"prettyPrinting":false,"lenient":false,"serializeSpecialFloatingPointValues":false,"dateStyle":2,"timeStyle":2,"longSerializationPolicy":"DEFAULT","builderFactories":[],"builderHierarchyFactories":[]},"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","\"6\"","\"7\"","\"8\""],"edges":[{"src":"\"1\"","dest":"\"2\"","weight":"1"},{"src":"\"1\"","dest":"\"3\"","weight":"1"},{"src":"\"5\"","dest":"\"4\"","weight":"5"},{"src":"\"6\"","dest":"\"2\"","weight":"2"},{"src":"\"5\"","dest":"\"3\"","weight":"2"},{"src":"\"8\"","dest":"\"7\"","weight":"9"},{"src":"\"4\"","dest":"\"6\"","weight":"6"},{"src":"\"2\"","dest":"\"5\"","weight":"4"}]}
|
||||
Reference in New Issue
Block a user