Refactoring

* Upgraded to JUnit5
* Enhanced the tests for multiple instances of graphs
* Save/Load test now pass

* Changed the hierarchy of classes:
  - Graph is now the main Abstract class for the graphs
  - GraphDirected is an Abstract class for directed graph and inherits Graph
  - GraphUndirected is an Abstract class for undirected graph and inherits Graph
* Changed how the Weight is represented in the graphs, removing the second parameter. From now on is only int.
* Updated the implementations for MatrixGraph, ListGraph and MapGraph
* Implemented only one undirected graph MatrixUndGraph
* Added UnionFind and one implementation: QuickFind
* Added MSF visit and implemented Kruskal and Prim (no tests)

* Changed all the graphic components due to the deletion of the second parameter in the Graph class
This commit is contained in:
2021-01-12 17:09:09 +01:00
parent 7f16252890
commit 9bda59dc7b
44 changed files with 3156 additions and 2536 deletions

View File

@@ -1,13 +1,15 @@
package berack96.lib.graph;
import java.util.Collection;
import java.util.List;
/**
* Class used for retrieving the edges of the graph.
*
* @param <V> the vertices
* @param <W> the weight of the edge
* @author Berack96
*/
public class Edge<V, W extends Number> {
public class Edge<V> implements Comparable<Edge<V>> {
/**
* The source vertex
@@ -20,21 +22,44 @@ public class Edge<V, W extends Number> {
/**
* The weight of this edge
*/
private final W weight;
private final int weight;
/**
* Create an final version of this object
* Create a final version of this object with weight 1
*
* @param source the source of the edge
* @param destination the destination of the edge
*/
public Edge(V source, V destination) {
this(source, destination, 1);
}
/**
* Create a final version of this object
*
* @param source the source of the edge
* @param destination the destination of the edge
* @param weight the weight of the edge
*/
public Edge(V source, V destination, W weight) {
public Edge(V source, V destination, int weight) {
this.source = source;
this.destination = destination;
this.weight = weight;
}
/**
*
*/
public Collection<V> getVertices() {
if (source == null && destination == null)
return List.of();
if (source == null)
return List.of(destination);
if (destination == null)
return List.of(source);
return List.of(source, destination);
}
/**
* The vertex where the edge goes
*
@@ -58,7 +83,7 @@ public class Edge<V, W extends Number> {
*
* @return the weight
*/
public W getWeight() {
public int getWeight() {
return weight;
}
@@ -80,4 +105,9 @@ public class Edge<V, W extends Number> {
return false;
}
}
@Override
public int compareTo(Edge<V> edge) {
return weight - edge.weight;
}
}

View File

@@ -1,56 +1,49 @@
package berack96.lib.graph;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.BFS;
import berack96.lib.graph.visit.impl.Dijkstra;
import berack96.lib.graph.visit.impl.VisitInfo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Consumer;
/**
* An interface for the graphs.<br>
* This interface is used for the graphs with Directed edges.<br>
* A directed edge between V1 and V2 is an edge that has V1 as source and V2 as destination.<br>
* An abstract class for the graphs.<br>
* This class is used for the graphs in general.<br>
* There are more specific {@link GraphDirected} and {@link GraphUndirected} edges graph interfaces.<br>
*
* @param <V> The Object that represent a vertex
* @param <W> The Object that represent the edge (more specifically the weight of the edge)
* @author Berack96
*/
public interface Graph<V, W extends Number> extends Iterable<V> {
public abstract class Graph<V> implements Iterable<V> {
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>
* A cycle is detected if visiting the graph G starting from V1 (that is any of the vertex of G),
* the visit can return to V1 in any point.
*
* @return true if has cycle, false otherwise
*/
boolean isCyclic();
public static final int NO_EDGE = 0;
public final static String NOT_CONNECTED = "The source vertex doesn't have a path that reach the destination";
public final static String PARAM_NULL = "The parameter must not be null";
public final static String VERTEX_NOT_CONTAINED = "The vertex must be contained in the graph";
/**
* Tells if the graph has the property of DAG (Directed Acyclic Graph).<br>
* A graph is a DAG only if absent of any cycle. ( see {@link #isCyclic()} )
*
* @return true if is a DAG, false otherwise
* Map that contains the vertex as key and a set of all the marker associated with it.
*/
boolean isDAG();
private final Map<V, Set<Object>> markers = new HashMap<>();
/**
* Get a new instance of this Graph.
*
* @return A new instance of the graph
*/
protected abstract Graph<V> getNewInstance();
/**
* Check if the vertex passed is contained in the graph or not.<br>
* The vertex V1 is contained in the graph G, if and only if:<br>
* exist V2 in G such that V2.equals(V1)
* exist V2 in G such that V2 == V1
*
* @param vertex the vertex to check
* @return true if the vertex is contained, false otherwise
* @throws NullPointerException if the vertex is null
*/
boolean contains(V vertex) throws NullPointerException;
public abstract boolean contains(V vertex) throws NullPointerException;
/**
* Get an instance of the vertex linked with this graph.<br>
@@ -58,29 +51,36 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
*
* @param vertex the vertex
* @return a vertex
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Vertex<V> get(V vertex) throws NullPointerException, IllegalArgumentException;
public final Vertex<V> get(V vertex) throws IllegalArgumentException {
checkVert(vertex);
return new Vertex<>(this, vertex);
}
/**
* 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.
* Add the vertex to the graph. If it's already in the graph it will be replaced and all its edges will be reset.<br>
* Of course the vertex added will have no marks nor edge to any other vertex nor form any other vertex.
*
* @param vertex the vertex to add
* @throws NullPointerException if the vertex is null
*/
void add(V vertex) throws NullPointerException;
public abstract void add(V vertex) throws NullPointerException;
/**
* Add the specified vertex to the graph only if the graph doesn't contains it.<br>
* The graph contains a vertex only if the method {@link #contains(Object)} returns true.
*
* @param vertex the vertex to add
* @return true if the vertex is added, false if the graph contains the vertex and therefore the new one is not added
* @return true if it adds a vertex, false if it was already in the graph
* @throws NullPointerException if the vertex is null
*/
boolean addIfAbsent(V vertex) throws NullPointerException;
public final boolean addIfAbsent(V vertex) throws NullPointerException {
if (contains(vertex))
return false;
add(vertex);
return true;
}
/**
* Add all the vertices contained in the collection to the graph.<br>
@@ -90,214 +90,178 @@ 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 addAll(Collection<V> vertices) throws NullPointerException;
public void addAll(@SuppressWarnings("ConstantConditions") Collection<V> vertices) throws NullPointerException {
check(vertices);
for (V vertex : vertices)
addIfAbsent(vertex);
}
/**
* Remove the selected vertex from the graph.<br>
* After this method's call the vertex will be no longer present in the graph, and nether all his edges.
* After this method's call the vertex will be no longer present in the graph, and nether all his edges and marks.
*
* @param vertex the vertex to remove
* @throws NullPointerException if the vertex is null
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained
*/
void remove(V vertex) throws NullPointerException, IllegalArgumentException;
public abstract 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 removeAll();
public void removeAll() {
unMarkAll();
for (V vertex : vertices())
remove(vertex);
}
/**
* Get all the marks of this graph.<br>
* Specifically it will return a collection of marks where every mark<br>
* as associated at least one vertex of the graph.<br>
* If the graph doesn't have vertex marked then it is returned an empty collection.
*
* @return a collection of marks
*/
Collection<Object> marks();
/**
* Add to the specified vertex the mark passed.<br>
* A vertex can have multiple marker.
*
* @param vertex the vertex to mark
* @param mark the mark to add
* @throws NullPointerException if one of the param is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException;
/**
* Remove the selected mark from the vertex.<br>
*
* @param vertex the vertex where remove the mark
* @param mark the mark to remove
* @throws NullPointerException if a param is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException;
/**
* Unmark the vertex selected.<br>
* After this call the vertex will not have any marked object to himself.
*
* @param vertex the vertex
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
void unMark(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Get all the vertices that are marked with the specific mark passed.<br>
* If there aren't vertices with that mark then it is returned an empty set.<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.
*
* @param mark the mark
* @return all the vertices that are marked with that specific mark
* @throws NullPointerException if the mark is null
*/
Collection<V> getMarkedWith(Object mark) throws NullPointerException;
/**
* Get all the marker of this vertex.<br>
* If the vertex doesn't have any mark, then it will return an empty set.<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.
*
* @param vertex the vertex
* @return all the mark to the vertex or an empty collection if none
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Remove the selected mark from all the vertices
*
* @param mark the mark to remove
* @throws NullPointerException if the mark is null
*/
void unMarkAll(Object mark) throws NullPointerException;
/**
* Remove all the marker to all the vertex.<br>
* After this call the {@link #getMarks(Object)} applied to any vertex will return an empty set
*/
void unMarkAll();
/**
* Add an edge between the two vertex.<br>
* The edge will be created from the vertex V1 and the vertex V2<br>
* This method will overwrite any existing edge between the two vertex.<br>
* If there was a previous edge then it is returned
* Check if the edge between the two vertex passed is contained in the graph or not.<br>
* If one of the two vertices is not contained in the graph, then even the edge isn't
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @param weight the weight of the edge
* @return null or the previous weight of the edge if there was already one
* @throws NullPointerException if one of the parameter is null
* @return true if the edge is contained, false otherwise
* @throws NullPointerException if one of the parameters is null
*/
public boolean containsEdge(V vertex1, V vertex2) throws NullPointerException {
try {
return getWeight(vertex1, vertex2) != NO_EDGE;
} catch (IllegalArgumentException ignore) {
return false;
}
}
/**
* Get the weight of the selected edge.<br>
* If the edge doesn't exist, then 0 is returned
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @return the weight previously set, or 0 if the edge doesn't exist
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
W addEdge(V vertex1, V vertex2, W weight) throws NullPointerException, IllegalArgumentException;
public abstract int getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException;
/**
* Add an edge between the two vertex.<br>
* The edge will be created from the vertex source of the edge and the vertex destination of it<br>
* This method will overwrite any existing edge between the two vertex.<br>
* If there was a previous edge then it is returned
*
* @param edge the edge to add
* @return null or the previous weight of the edge if there was already one
* @return 0 or the previous weight of the edge if there was already one
* @throws NullPointerException if one of the parameter is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
W addEdge(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException;
public final int addEdge(Edge<V> edge) throws NullPointerException, IllegalArgumentException {
return addEdge(edge.getSource(), edge.getDestination(), edge.getWeight());
}
/**
* This particular function add an edge to the graph.<br>
* If one of the two, or both vertices aren't contained in the graph, then the vertices will be added.<br>
* The edge will be created from the vertex V1 and the vertex V2<br>
* Add an edge between the two vertex.<br>
* This method will overwrite any existing edge between the two vertices.<br>
* By default using this method will set the edge to the value 1.
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @throws NullPointerException if one of the parameter is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
public final void addEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
addEdge(vertex1, vertex2, 1);
}
/**
* Add an edge between the two vertex.<br>
* This method will overwrite any existing edge between the two vertex.<br>
* If there was a previous edge then it is returned
* If there was a previous edge then it's value is returned.<br>
* If the weight passed is equals to 0 or {@link Graph#NO_EDGE}, then
* the edge will be removed.
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @param weight the weight of the edge
* @return null or the previous weight of the edge if there was already one
* @throws NullPointerException if one of the parameter is null
* @return 0 or the previous weight of the edge if there was already one
* @throws NullPointerException if one of the parameter is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
W addEdgeAndVertices(V vertex1, V vertex2, W weight) throws NullPointerException;
public abstract int addEdge(V vertex1, V vertex2, int weight) throws NullPointerException, IllegalArgumentException;
/**
* This particular function add an edge to the graph.<br>
* If one of the two, or both vertices of the edge aren't contained in the graph, then the vertices will be added.<br>
* The edge will be created from the vertex source of the edge and the vertex destination of it<br>
* This method will overwrite any existing edge between the two vertex.<br>
* This method will overwrite any existing edge between the two vertices.<br>
* If there was a previous edge then it is returned
*
* @param edge the edge to add
* @return null or the previous weight of the edge if there was already one
* @return 0 or the previous weight of the edge if there was already one
* @throws NullPointerException if one of the parameter is null
*/
W addEdgeAndVertices(Edge<V, W> edge) throws NullPointerException, IllegalArgumentException;
public final int addEdgeAndVertices(Edge<V> edge) throws NullPointerException, IllegalArgumentException {
return addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight());
}
/**
* This particular function add an edge to the graph.<br>
* If one of the two, or both vertices aren't contained in the graph, then the vertices will be added.<br>
* This method will overwrite any existing edge between the two vertices.<br>
* By default using this method will set the edge to the value 1.
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @throws NullPointerException if one of the parameter is null
*/
public final int addEdgeAndVertices(V vertex1, V vertex2) throws NullPointerException {
return addEdgeAndVertices(vertex1, vertex2, 1);
}
/**
* This particular function add an edge to the graph.<br>
* If one of the two, or both vertices aren't contained in the graph, then the vertices will be added.<br>
* This method will overwrite any existing edge between the two vertices.<br>
* If there was a previous edge then it is returned
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @param weight the weight of the edge
* @return 0 or the previous weight of the edge if there was already one
* @throws NullPointerException if one of the parameter is null
*/
public final int addEdgeAndVertices(V vertex1, V vertex2, int weight) throws NullPointerException {
addIfAbsent(vertex1);
addIfAbsent(vertex2);
return addEdge(vertex1, vertex2, weight);
}
/**
* Add all the edges of the collection to the graph.<br>
* If one of the two, or both vertices aren't contained in the graph, then the vertices will be added.<br>
* Any null edges will be ignored.<br>
* This method will overwrite any existing edge between the two vertex.
* This method will overwrite any existing edge between the two vertices.
*
* @param edges the edges to add
* @throws NullPointerException if the set is null
*/
void addAllEdges(Collection<Edge<V, W>> edges) throws NullPointerException;
public void addAllEdges(Collection<Edge<V>> edges) throws NullPointerException {
edges.forEach(edge -> addEdgeAndVertices(edge.getSource(), edge.getDestination(), edge.getWeight()));
}
/**
* Get the weight of the selected edge.<br>
* If the edge doesn't exist, then null is returned
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @return the weight previously set, or null if the edge doesn't exist
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
W getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException;
/**
* Remove the edge between the two vertex.<br>
* Remove the edge between the two vertex by setting it's value to 0.<br>
* If the edge doesn't exist, then this call does nothing.<br>
* After this method's call it will be no longer possible to travel from V1 to V2, nether from V2 to V1.
* This method is equivalent to calling {@link Graph#addEdge(Object, Object, int)} )}
* with the weight set to {@link Graph#NO_EDGE}
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException;
/**
* Remove all the edges that goes in the vertex.<br>
* After this method's call it will be no longer possible travel to this vertex.
*
* @param vertex a vertex of the graph
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Remove all the edges that start from this vertex.<br>
* After this method's call it will be no longer possible travel to any vertex from this one.
*
* @param vertex a vertex of the graph
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException;
public void removeEdge(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
addEdge(vertex1, vertex2, NO_EDGE);
}
/**
* Remove all edges form a particular vertex of the graph.<br>
@@ -308,133 +272,199 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException;
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
unMark(vertex);
remove(vertex);
add(vertex);
}
/**
* Remove all the edges of the graph.<br>
* After this method's call the graph will have only vertices, and no edge.
*/
void removeAllEdge();
/**
* Check if the edge between the two vertex passed is contained in the graph or not.<br>
* An edge between V1 and V2 is contained in the graph if and only if i can travel from V1 to V2.<br>
* If one of the two vertices is not contained in the graph, then even the edge isn't
*
* @param vertex1 a vertex of the graph
* @param vertex2 a vertex of the graph
* @return true if the edge is contained, false otherwise
* @throws NullPointerException if one of the parameters is null
*/
boolean containsEdge(V vertex1, V vertex2) throws NullPointerException;
/**
* Get all the vertices in the graph.<br>
* If the graph doesn't contains vertices, it'll return an empty collection.<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.
*
* @return an array that include all the vertices
*/
Collection<V> vertices();
/**
* Get all the edges in the graph.<br>
* If the graph doesn't contains edges, it'll return an empty collection.<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.
*
* @return a collection that include all the edges
*/
Collection<Edge<V, W>> edges();
public void removeAllEdge() {
Collection<V> vertices = vertices();
removeAll();
addAll(vertices);
}
/**
* Retrieve all the edges of a particular vertex.<br>
* Note: the edges that are returned are the one that goes IN this vertex AND the edges that goes OUT of it.<br>
* Note2: depending on the implementation, modifying the returned collection<br>
* could affect the graph behavior and the changes could be reflected to the graph.
*
* @param vertex a vertex of the graph
* @return a collection of edges
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Collection<Edge<V, W>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Retrieve all the edges of a particular vertex.<br>
* Note: the edges that are returned are the one that have this vertex as destination and another as source.<br>
* Note2: depending on the implementation, modifying the returned collection<br>
* could affect the graph behavior and the changes could be reflected to the graph.
*
* @param vertex a vertex of the graph
* @return a collection of edges
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Collection<Edge<V, W>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Retrieve all the edges that goes OUT of a particular vertex.<br>
* Note: the edges that are returned are the one that have this vertex as source and another one as destination.<br>
* Note2: depending on the implementation, modifying the returned collection<br>
* could affect the graph behavior and the changes could be reflected to the graph.
*
* @param vertex a vertex of the graph
* @return a collection of edges
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Collection<Edge<V, W>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException;
public abstract Collection<Edge<V>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Get all the vertices that are children of the vertex passed as parameter.<br>
* The vertices V(0-N) that are 'children' of a vertex V1, are all the vertices that have an edge
* where V1 is the source of that edge.<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.
* where V1 is the source of that edge.
*
* @param vertex the source vertex
* @return an array of vertices
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
Collection<V> getChildrens(V vertex) throws NullPointerException, IllegalArgumentException;
public abstract Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Get all the vertices that have the vertex passed as their child.<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.
* Basically is the opposite of {@link #getChildren(Object)}
*
* @param vertex a vertex of the graph
* @return an array of ancestors of the vertex
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException;
public abstract Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Tells the degree of all the edges that goes to this vertex.<br>
* Basically, it'll count how many edge towards himself it have.
* Get all the marks of this graph.<br>
* Specifically it will return a collection of marks where every mark<br>
* as associated at least one vertex of the graph.<br>
* If the graph doesn't have vertex marked then it is returned an empty collection.
*
* @param vertex a vertex of the graph
* @return the in degree of the vertex
* @return a collection of marks
*/
public final Collection<Object> marks() {
Collection<Object> ret = new HashSet<>();
markers.forEach((v, set) -> ret.addAll(set));
return ret;
}
/**
* Add to the specified vertex the mark passed.<br>
* A vertex can have multiple marker.<br>
* The null marker cannot be used.
*
* @param vertex the vertex to mark
* @param mark the mark to add
* @throws NullPointerException if one of the param is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
public final void mark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
check(mark);
checkVert(vertex);
Set<Object> marks = markers.computeIfAbsent(vertex, v -> new HashSet<>());
marks.add(mark);
}
/**
* Remove the selected mark from the vertex.<br>
*
* @param vertex the vertex where remove the mark
* @param mark the mark to remove
* @throws NullPointerException if a param is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
public final void unMark(V vertex, Object mark) throws NullPointerException, IllegalArgumentException {
check(mark);
checkVert(vertex);
markers.computeIfPresent(vertex, (v, set) -> {
set.remove(mark);
if (set.size() > 0)
return set;
return null;
});
}
/**
* Unmark the vertex selected.<br>
* After this call the vertex will not have any marked object to himself.
*
* @param vertex the vertex
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException;
public final void unMark(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
try {
markers.remove(vertex).clear();
} catch (Exception ignore) {
}
}
/**
* Tells the degree of all the edges that goes form this vertex to others.<br>
* Basically, it'll count how many edge towards any other vertex it have.
* Get all the vertices that are marked with the specific mark passed.<br>
* If there aren't vertices with that mark then it is returned an empty set.<br>
*
* @param vertex a vertex of the graph
* @return the out degree of the vertex
* @param mark the mark
* @return all the vertices that are marked with that specific mark
* @throws NullPointerException if the mark is null
*/
public final Collection<V> getMarkedWith(Object mark) throws NullPointerException {
check(mark);
Collection<V> vertices = new ArrayList<>(markers.size());
markers.forEach((v, set) -> {
if (set.contains(mark))
vertices.add(v);
});
return vertices;
}
/**
* Get all the marker of this vertex.<br>
* If the vertex doesn't have any mark, then it will return an empty set.<br>
* Note: modifying the returned collection affect the marker of the vertex.
*
* @param vertex the vertex
* @return all the mark to the vertex or an empty collection if none
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException;
public final Collection<Object> getMarks(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
return markers.getOrDefault(vertex, new HashSet<>());
}
/**
* Remove the selected mark from all the vertices
*
* @param mark the mark to remove
* @throws NullPointerException if the mark is null
*/
public final void unMarkAll(Object mark) throws NullPointerException {
check(mark);
Collection<V> toRemove = new ArrayList<>(markers.size());
markers.forEach((v, set) -> {
set.remove(mark);
if (set.size() == 0)
toRemove.add(v);
});
markers.keySet().removeAll(toRemove);
}
/**
* Remove all the marker to all the vertex.<br>
* After this call the {@link #getMarks(Object)} applied to any vertex will return an empty set
*/
public final void unMarkAll() {
markers.values().forEach(Set::clear);
markers.clear();
}
/**
* Get all the vertices in the graph.<br>
* If the graph doesn't contains vertices, it'll return an empty collection.<br>
*
* @return an array that include all the vertices
*/
public Collection<V> vertices() {
Collection<V> collection = new ArrayList<>();
forEach(collection::add);
return collection;
}
/**
* Get all the edges in the graph.<br>
* If the graph doesn't contains edges, it'll return an empty collection.<br>
*
* @return a collection that include all the edges
*/
public abstract Collection<Edge<V>> edges();
/**
* Tells the degree of a vertex.<br>
@@ -446,63 +476,36 @@ 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
*/
int degree(V vertex) throws NullPointerException, IllegalArgumentException;
public abstract int degree(V vertex) throws NullPointerException, IllegalArgumentException;
/**
* Tells how many vertices are in the graph.
*
* @return the number of vertices
*/
int size();
public abstract int size();
/**
* Tells how many edges are in the graph.
*
* @return the number of edges
*/
int numberOfEdges();
public abstract int numberOfEdges();
/**
* Visit the graph accordingly to the strategy that is passed.<br>
* This method visit the graph from the source to all the vertex that are reachable form the source.<br>
* Some strategy can accept a source vertex null, because they visit all the graph anyway.
*
* @param source the source vertex of the visit
* @param source the starting vertex for the visit
* @param strategy the algorithm for visiting the graph
* @param visit the function to apply at each vertex
* @return an info of the visit
* @throws NullPointerException if one of the parameter is null (except the consumer)
* @throws IllegalArgumentException if the vertex is not in the graph
* @param visit the function to apply at each vertex visited
* @return an info of the visit if provided by the strategy
* @throws NullPointerException if one of the parameter is null (except the consumer)
* @throws UnsupportedOperationException in the case the visit cannot be applied to the graph
*/
VisitInfo<V> visit(V source, VisitStrategy<V, W> strategy, Consumer<V> visit) throws NullPointerException, IllegalArgumentException;
/**
* This method will create a new Graph that is the transposed version of the original.<br>
* At the end of this method the new graph will have all the edges inverted in orientation.<br>
* Example: if the graph G contains (V1, V2, V3) as vertex, and (V1-&gt;V2, V3-&gt;V2) as edges,
* the transpose graph G' will contain (V1, V2, V3) as vertex, and (V2-&gt;V1, V2-&gt;V3) as edges.
*
* @return a transposed graph of this instance
*/
Graph<V, W> transpose();
/**
* If the current graph is a DAG, it returns a topological sort of this graph.<br>
* 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 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;
/**
* The strongly connected components or disconnected components of an arbitrary directed graph
* form a partition into subgraphs that are themselves strongly connected.
*
* @return a collection containing the strongly connected components
*/
Collection<Collection<V>> stronglyConnectedComponents();
public final VisitInfo<V> visit(V source, VisitStrategy<V> strategy, Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
return strategy.visit(this, source, visit);
}
/**
* Get a sub-graph of the current one based on the maximum depth that is given.<br>
@@ -517,18 +520,57 @@ 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
*/
Graph<V, W> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException;
public final Graph<V> subGraph(V source, int depth) throws NullPointerException, IllegalArgumentException {
checkVert(source);
Graph<V> sub = getNewInstance();
Set<V> vertices = new HashSet<>(this.size() + 1, 1);
new BFS<V>().setMaxDepth(Math.max(depth, 0)).visit(this, source, vertices::add);
sub.addAll(vertices);
for (V src : vertices)
for (V dest : getChildren(src))
if (sub.contains(dest))
sub.addEdge(new Edge<>(src, dest, this.getWeight(src, dest)));
return sub;
}
/**
* Get a sub-graph of the current one with only the vertex marked with the selected markers.<br>
* Each vertex will have all his edges, but only the ones with the destination marked with the same marker.<br>
* Each vertex will have all his markers and his edges, but only the ones with the destination marked with the same marker.<br>
* If the marker is not specified or is null then the returning graph will have all the vertices that are not marked by any marker.<br>
* If the graph doesn't contain any vertex with that marker then an empty graph is returned.
*
* @param marker one or more markers
* @return a sub-graph of the current graph
*/
Graph<V, W> subGraph(Object...marker);
public final Graph<V> subGraph(Object... marker) {
final Graph<V> 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((v, set) -> {
if (!Collections.disjoint(allMarkers, set))
allVertices.add(v);
});
} else {
Collection<V> toAdd = vertices();
toAdd.removeAll(markers.keySet());
allVertices.addAll(toAdd);
}
sub.addAll(allVertices);
for (V src : sub.vertices()) {
for (Object mark : getMarks(src))
sub.mark(src, mark);
for (V dest : getChildren(src))
if (sub.contains(dest))
sub.addEdge(src, dest, getWeight(src, dest));
}
return sub;
}
/**
* Get the minimum path from the source vertex to the destination vertex.<br>
@@ -541,7 +583,13 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @throws IllegalArgumentException if the vertex is not in the graph
* @throws UnsupportedOperationException if from the source it's not possible to reach the destination
*/
List<Edge<V, W>> distance(V source, V destination) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException;
public final List<Edge<V>> distance(V source, V destination) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
checkVert(source, destination);
List<Edge<V>> path = distance(source).get(destination);
if (path == null)
throw new UnsupportedOperationException(NOT_CONNECTED);
return path;
}
/**
* Get the minimum path from the source vertex to all the possible reachable vertices.
@@ -551,7 +599,40 @@ public interface Graph<V, W extends Number> extends Iterable<V> {
* @throws NullPointerException if one of the parameter is null (except the consumer)
* @throws IllegalArgumentException if the vertex is not in the graph
*/
Map<V, List<Edge<V, W>>> distance(V source) throws NullPointerException, IllegalArgumentException;
public final Map<V, List<Edge<V>>> distance(V source) throws NullPointerException, IllegalArgumentException {
checkVert(source);
Dijkstra<V> dijkstra = new Dijkstra<>();
dijkstra.visit(this, source, null);
return dijkstra.getLastDistance();
}
// TODO maybe, but i don't think so... STATIC DISTANCE V* -> V*
/**
* Check if the object passed is not null.
* If it's null then throws eventual exception
*
* @param objects the objects to test
*/
protected final void check(Object... objects) {
for (Object obj : objects)
if (obj == null)
throw new NullPointerException(PARAM_NULL);
}
/**
* Check if the vertex passed is not null and if exist in the graph.
* If not then throws eventual exception
*
* @param vertices the vertices to test
*/
@SafeVarargs
protected final void checkVert(V... vertices) {
check((Object[]) vertices);
for (V vert : vertices)
try {
if (!contains(vert))
throw new IllegalArgumentException(VERTEX_NOT_CONTAINED);
} catch (ClassCastException ignore) {
}
}
}

View File

@@ -0,0 +1,207 @@
package berack96.lib.graph;
import berack96.lib.graph.visit.VisitSCC;
import berack96.lib.graph.visit.VisitTopological;
import berack96.lib.graph.visit.impl.Tarjan;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/**
* This is a more specific interface for an implementation of a Undirected Graph.<br>
* An Undirected Graph is a Graph where an arc or edge can be traversed in both ways.<br>
* For example an arc between A and B can be traversed even from B to A.<br>
*
* @param <V> The Object that represent a vertex
* @author Berack96
*/
public abstract class GraphDirected<V> extends Graph<V> {
String NOT_DAG = "The graph is not a DAG";
/**
* Tells if the graph has some cycle.<br>
* A cycle is detected if visiting the graph G starting from V1 (that is any of the vertex of G),
* the visit can return to V1 in any point.
*
* @return true if has cycle, false otherwise
*/
public final boolean isCyclic() {
return stronglyConnectedComponents().size() != size();
}
/**
* Tells if the graph has the property of DAG (Directed Acyclic Graph).<br>
* A graph is a DAG only if absent of any cycle. ( see {@link #isCyclic()} )
*
* @return true if is a DAG, false otherwise
*/
public final boolean isDAG() {
return !isCyclic();
}
/**
* Remove all the edges that goes in the vertex.<br>
* After this method's call it will be no longer possible travel to this vertex.
*
* @param vertex a vertex of the graph
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
public void removeAllInEdge(V vertex) throws NullPointerException, IllegalArgumentException {
for (V ancestor : getAncestors(vertex))
removeEdge(ancestor, vertex);
}
/**
* Remove all the edges that start from this vertex.<br>
* After this method's call it will be no longer possible travel to any vertex from this one.
*
* @param vertex a vertex of the graph
* @throws NullPointerException if one of the parameters is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
public void removeAllOutEdge(V vertex) throws NullPointerException, IllegalArgumentException {
for (V child : getChildren(vertex))
removeEdge(vertex, child);
}
/**
* Retrieve all the edges of a particular vertex.<br>
* Note: the edges that are returned are the one that have this vertex as destination and another as source.<br>
* Note2: depending on the implementation, modifying the returned collection<br>
* could affect the graph behavior and the changes could be reflected to the graph.
*
* @param vertex a vertex of the graph
* @return a collection of edges
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
public Collection<Edge<V>> getEdgesIn(V vertex) throws NullPointerException, IllegalArgumentException {
Collection<V> ancestors = getAncestors(vertex);
Collection<Edge<V>> edgesIn = new HashSet<>(ancestors.size());
for (V ancestor : ancestors) {
int weight = getWeight(ancestor, vertex);
if (weight != NO_EDGE)
edgesIn.add(new Edge<>(ancestor, vertex, weight));
}
return edgesIn;
}
/**
* Retrieve all the edges that goes OUT of a particular vertex.<br>
* Note: the edges that are returned are the one that have this vertex as source and another one as destination.<br>
* Note2: depending on the implementation, modifying the returned collection<br>
* could affect the graph behavior and the changes could be reflected to the graph.
*
* @param vertex a vertex of the graph
* @return a collection of edges
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
public Collection<Edge<V>> getEdgesOut(V vertex) throws NullPointerException, IllegalArgumentException {
Collection<V> children = getChildren(vertex);
Collection<Edge<V>> edgesOut = new HashSet<>(children.size());
for (V child : children) {
int weight = getWeight(vertex, child);
if (weight != NO_EDGE)
edgesOut.add(new Edge<>(vertex, child, weight));
}
return edgesOut;
}
/**
* Tells the degree of all the edges that goes to this vertex.<br>
* Basically, it'll count how many edge towards himself it have.
*
* @param vertex a vertex of the graph
* @return the in degree of the vertex
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
return getAncestors(vertex).size();
}
/**
* Tells the degree of all the edges that goes form this vertex to others.<br>
* Basically, it'll count how many edge towards any other vertex it have.
*
* @param vertex a vertex of the graph
* @return the out degree of the vertex
* @throws NullPointerException if the vertex is null
* @throws IllegalArgumentException if the vertex is not contained in the graph
*/
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
return getChildren(vertex).size();
}
/**
* This method will create a new Graph that is the transposed version of the original.<br>
* At the end of this method the new graph will have all the edges inverted in orientation.<br>
* Example: if the graph G contains (V1, V2, V3) as vertex, and (V1-&gt;V2, V3-&gt;V2) as edges,
* the transpose graph G' will contain (V1, V2, V3) as vertex, and (V2-&gt;V1, V2-&gt;V3) as edges.
*
* @return a transposed graph of this instance
*/
public final GraphDirected<V> transpose() {
GraphDirected<V> transposed = (GraphDirected<V>) getNewInstance();
transposed.addAll(vertices());
for (V vertex : transposed)
for (V child : getChildren(vertex))
transposed.addEdge(child, vertex, getWeight(vertex, child));
return transposed;
}
/**
* If the current graph is a DAG, it returns a topological sort of this graph.<br>
* 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 a list containing the topological order of the vertices
* @throws UnsupportedOperationException if the graph is not a DAG (see {@link #isDAG()})
*/
public final List<V> topologicalSort() throws UnsupportedOperationException {
VisitTopological<V> visit = new Tarjan<>();
visit.visit(this, null, null);
if (visit.getTopologicalSort() == null)
throw new UnsupportedOperationException(NOT_DAG);
return visit.getTopologicalSort();
}
/**
* The strongly connected components or disconnected components of an arbitrary directed graph
* form a partition into subgraphs that are themselves strongly connected.
*
* @return a collection containing the strongly connected components
*/
public final Collection<Collection<V>> stronglyConnectedComponents() {
VisitSCC<V> visit = new Tarjan<>();
visit.visit(this, null, null);
return visit.getSCC();
}
@Override
public Collection<Edge<V>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
Collection<Edge<V>> edges = getEdgesIn(vertex);
edges.addAll(getEdgesOut(vertex));
return edges;
}
@Override
public Collection<Edge<V>> edges() {
Collection<Edge<V>> collection = new ArrayList<>();
forEach(v -> collection.addAll(getEdgesIn(v)));
return collection;
}
@Override
public final int degree(V vertex) throws NullPointerException, IllegalArgumentException {
return degreeIn(vertex) + degreeOut(vertex);
}
}

View File

@@ -0,0 +1,46 @@
package berack96.lib.graph;
import berack96.lib.graph.visit.VisitMST;
import berack96.lib.graph.visit.impl.Prim;
import java.util.Collection;
import java.util.LinkedList;
/**
* This is a more specific interface for an implementation of a Directed Graph.<br>
* A Directed Graph is a Graph where an arc or edge can be traversed in only one way.<br>
* A directed edge between V1 and V2 is an edge that has V1 as source and V2 as destination.<br>
*
* @param <V> The Object that represent a vertex
* @author Berack96
*/
public abstract class GraphUndirected<V> extends Graph<V> {
/**
* The connected components of an arbitrary undirected graph form a partition into subgraphs that are themselves connected.
*
* @return a collection containing the strongly connected components
*/
public Collection<Collection<V>> connectedComponents() {
return null;
}
/**
* minimum spanning forest or minimum spamming tree of the graph
*
* @return A collection of edges representing the M.S.F.
*/
public Collection<Edge<V>> minimumSpanningForest() {
VisitMST<V> visit = new Prim<>();
visit.visit(this, iterator().next(), null);
return visit.getMST();
}
@Override
public Collection<Edge<V>> edgesOf(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
Collection<Edge<V>> edges = new LinkedList<>();
getChildren(vertex).forEach(v -> edges.add(new Edge<>(vertex, v, getWeight(vertex, v))));
return edges;
}
}

View File

@@ -3,8 +3,9 @@ package berack96.lib.graph;
import berack96.lib.graph.visit.VisitStrategy;
import berack96.lib.graph.visit.impl.VisitInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -15,7 +16,6 @@ import java.util.function.Consumer;
* @param <V> the vertex
* @author Berack96
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class Vertex<V> {
public static final String REMOVED = "The vertex is no longer in the graph";
@@ -27,7 +27,7 @@ public class Vertex<V> {
/**
* The graph associated
*/
private final Graph<V, Number> graph;
private final Graph<V> graph;
/**
* Get a Vertex linked with the graph
@@ -36,10 +36,10 @@ public class Vertex<V> {
* @param vertex the vertex
* @throws NullPointerException if one of the param is null
*/
public Vertex(Graph<V, ?> graph, V vertex) throws NullPointerException {
public Vertex(Graph<V> graph, V vertex) throws NullPointerException {
if (graph == null || vertex == null)
throw new NullPointerException();
this.graph = (Graph<V, Number>) graph;
this.graph = graph;
this.vertex = vertex;
}
@@ -48,7 +48,7 @@ public class Vertex<V> {
*
* @return the vertex
*/
public V getValue() {
public V get() {
return vertex;
}
@@ -105,22 +105,22 @@ public class Vertex<V> {
*/
public Collection<V> getChildren() throws UnsupportedOperationException {
throwIfNotContained();
return graph.getChildrens(vertex);
return graph.getChildren(vertex);
}
/**
* Get all the children of this vertex like {@link #getChildren()}, but as {@link Vertex}.<br>
* In this way they are linked to the graph as this one.<br>
* * This method allocate a new object for each vertex, so it is more heavy.
* This method allocate a new object for each vertex, so it is more heavy.
*
* @return a collection of vertices that are children of the current one
* @throws UnsupportedOperationException if the vertex is not in the graph anymore
*/
public Collection<Vertex<V>> getChildrenAsVertex() throws UnsupportedOperationException {
Collection<V> children = getChildren();
Collection<Vertex<V>> toReturn = new HashSet<>();
Collection<Vertex<V>> toReturn = new ArrayList<>(children.size());
for (V vertex : children)
toReturn.add(new Vertex<>(graph, vertex));
toReturn.add(graph.get(vertex));
return toReturn;
}
@@ -147,33 +147,24 @@ public class Vertex<V> {
*/
public Collection<Vertex<V>> getAncestorsAsVertex() throws UnsupportedOperationException {
Collection<V> ancestors = getAncestors();
Collection<Vertex<V>> toReturn = new HashSet<>();
Collection<Vertex<V>> toReturn = new ArrayList<>(ancestors.size());
for (V vertex : ancestors)
toReturn.add(new Vertex<>(graph, vertex));
toReturn.add(graph.get(vertex));
return toReturn;
}
/**
* Get all the edge that goes OUT of this vertex
* This method will return the weight of the edge that connects<br>
* this vertex to the vertex inserted.<br>
* In the case that the two vertices aren't connected this method will return 0.
*
* @return a collection of edges with source this one
* @throws UnsupportedOperationException if the vertex is not in the graph anymore
* @param child a child of this vertex
* @return the weight to the child or 0 if the edge doesn't exist.
*/
public Collection<Edge<V, Number>> getEdgesOut() throws UnsupportedOperationException {
public int getChildWeight(V child) {
throwIfNotContained();
return graph.getEdgesOut(vertex);
}
/**
* Get all the edge that goes INTO this vertex
*
* @return a collection of edges with destination this one
* @throws UnsupportedOperationException if the vertex is not in the graph anymore
*/
public Collection<Edge<V, Number>> getEdgesIn() throws UnsupportedOperationException {
throwIfNotContained();
return graph.getEdgesIn(vertex);
return graph.getWeight(vertex, child);
}
/**
@@ -186,11 +177,26 @@ public class Vertex<V> {
* @throws IllegalArgumentException if the child vertex is not contained in the graph
* @throws UnsupportedOperationException if the vertex is not in the graph anymore
*/
public void addChild(V child, Number weight) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
public void addChild(V child, int weight) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
throwIfNotContained();
graph.addEdge(vertex, child, weight);
}
/**
* Add a child to this vertex.<br>
* The added child must be in the graph or it will return an exception.<br>
* This method will add the basic value for the weight provided by the graph. {@link Graph#addEdge(V, V)}
*
* @param child the destination vertex of this edge
* @throws NullPointerException if the param is null
* @throws IllegalArgumentException if the child vertex is not contained in the graph
* @throws UnsupportedOperationException if the vertex is not in the graph anymore
*/
public void addChild(V child) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException {
throwIfNotContained();
graph.addEdge(vertex, child);
}
/**
* Removes a child of this vertex.
* If the vertex passed as param is not a child, then this call does nothing.
@@ -240,9 +246,10 @@ 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<V, ?> strategy, final Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
@SuppressWarnings("ConstantConditions")
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);
return graph.visit(vertex, strategy, visit);
}
@Override
@@ -252,13 +259,13 @@ public class Vertex<V> {
@Override
public int hashCode() {
return toString().hashCode();
return vertex.hashCode();
}
@Override
public boolean equals(Object obj) {
try {
return obj instanceof Vertex && (this.vertex.equals(obj) || this.vertex.equals(((Vertex) obj).vertex));
return obj instanceof Vertex && (Objects.equals(vertex, obj) || Objects.equals(vertex, ((Vertex<?>) obj).vertex));
} catch (Exception e) {
return false;
}

View File

@@ -1,579 +0,0 @@
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;
}
}

View File

@@ -1,20 +1,20 @@
package berack96.lib.graph.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.GraphDirected;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 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> {
public class ListGraph<V> extends GraphDirected<V> {
final private Map<V, List<Adj>> adj = new HashMap<>();
final private Map<V, List<Adj>> adj = new Hashtable<>();
@Override
public Iterator<V> iterator() {
@@ -22,121 +22,137 @@ public class ListGraph<V, W extends Number> extends AGraph<V, W> {
}
@Override
protected Graph<V, W> getNewInstance() {
protected Graph<V> getNewInstance() {
return new ListGraph<>();
}
@Override
protected void addVertex(V vertex) {
adj.put(vertex, new LinkedList<>());
public void add(V vertex) {
check(vertex);
if (adj.containsKey(vertex))
removeAllEdge(vertex);
else
adj.put(vertex, new LinkedList<>());
}
@Override
protected boolean containsVertex(V vertex) {
public boolean contains(V vertex) {
check(vertex);
return adj.containsKey(vertex);
}
@Override
protected void removeVertex(V vertex) {
public void remove(V vertex) {
checkVert(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);
});
adj.forEach((v, list) -> list.remove(getAdj(list, vertex)));
}
@Override
protected void removeAllVertices() {
public int addEdge(V vertex1, V vertex2, int weight) {
checkVert(vertex1, vertex2);
List<Adj> list = adj.get(vertex1);
Adj a = getAdj(list, vertex2);
int old = a == null ? NO_EDGE : a.weight;
if (weight == NO_EDGE)
list.remove(a);
else if (old == NO_EDGE)
list.add(new Adj(vertex2, weight));
else
a.weight = weight;
return old;
}
@Override
public int getWeight(V vertex1, V vertex2) {
checkVert(vertex1, vertex2);
Adj a = getAdj(adj.get(vertex1), vertex2);
return a == null ? NO_EDGE : a.weight;
}
@Override
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
Collection<V> children = new HashSet<>();
for (Adj adj : adj.get(vertex))
children.add(adj.vertex);
return children;
}
@Override
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
Collection<V> ancestors = new HashSet<>();
adj.forEach((v, list) -> {
if (getAdj(list, vertex) != null)
ancestors.add(v);
});
return ancestors;
}
/**
* From here on there are some optimization for the methods of the generic DirectedGraph
**/
@Override
public int size() {
return adj.size();
}
@Override
public int numberOfEdges() {
AtomicInteger size = new AtomicInteger(0);
adj.values().forEach(list -> size.addAndGet(list.size()));
return size.get();
}
@Override
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
AtomicInteger degree = new AtomicInteger(0);
adj.values().forEach(list -> degree.addAndGet(getAdj(list, vertex) != null ? 1 : 0));
return degree.get();
}
@Override
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
return adj.get(vertex).size();
}
@Override
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
adj.get(vertex).clear();
adj.forEach((v, list) -> list.remove(getAdj(list, vertex)));
}
@Override
public void removeAllEdge() {
adj.forEach((v, list) -> list.clear());
}
@Override
public void removeAll() {
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;
private Adj getAdj(List<Adj> list, V vertex) {
for (Adj adj : list)
if (Objects.equals(adj.vertex, vertex))
return adj;
return null;
}
@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) {
private int weight;
private Adj(V vertex, int weight) {
this.vertex = vertex;
this.weight = weight;
}

View File

@@ -1,7 +1,7 @@
package berack96.lib.graph.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.GraphDirected;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@@ -14,97 +14,92 @@ import java.util.concurrent.atomic.AtomicInteger;
* This happen if the HashMap is not reallocated. So in the end each operation of adding or removing has O(n)
*
* @param <V> the vertices
* @param <W> the weight of the edges
* @author Berack96
*/
public class MapGraph<V, W extends Number> extends AGraph<V, W> {
public class MapGraph<V> extends GraphDirected<V> {
/**
* Map that contains the edges from a vertex to another<br>
* The first vertex is the vertex where start the edge, the second one is where the edge goes<br>
* If an edge exist, then it's weight is returned
*/
private final Map<V, Map<V, W>> edges = new HashMap<>();
@Override
public Iterator<V> iterator() {
return edges.keySet().iterator();
}
/**
* Map that contains the edges from a vertex to another<br>
* The first vertex is the vertex where start the edge, the second one is where the edge goes<br>
* If an edge exist, then it's weight is returned
*/
private final Map<V, Map<V, Integer>> edges = new HashMap<>();
@Override
public Iterator<V> iterator() {
return edges.keySet().iterator();
}
@Override
protected Graph<V, W> getNewInstance() {
protected Graph<V> getNewInstance() {
return new MapGraph<>();
}
@Override
protected void addVertex(V vertex) {
edges.put(vertex, new HashMap<>());
public void add(V vertex) {
check(vertex);
edges.computeIfAbsent(vertex, v -> new HashMap<>());
edges.forEach((v, adj) -> adj.remove(vertex));
edges.get(vertex).clear();
}
@Override
protected boolean containsVertex(V vertex) {
public boolean contains(V vertex) {
check(vertex);
return edges.containsKey(vertex);
}
@Override
protected void removeVertex(V vertex) {
public void remove(V vertex) {
checkVert(vertex);
edges.remove(vertex);
edges.forEach((v, map) -> map.remove(vertex));
edges.forEach((v, map) -> map.remove(vertex));
}
@Override
protected void removeAllVertices() {
edges.clear();
public int addEdge(V vertex1, V vertex2, int weight) {
checkVert(vertex1, vertex2);
Map<V, Integer> edge = edges.get(vertex1);
Integer old = edge.get(vertex2);
old = old == null ? NO_EDGE : old;
if (weight == NO_EDGE)
edge.remove(vertex2);
else
edge.put(vertex2, weight);
return old;
}
@Override
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
return contains(vertex1) && contains(vertex2) && edges.get(vertex1).containsKey(vertex2);
public int getWeight(V vertex1, V vertex2) {
checkVert(vertex1, vertex2);
Integer weight = edges.get(vertex1).get(vertex2);
return weight == null ? NO_EDGE : weight;
}
@Override
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
return edges.get(vertex1).put(vertex2, weight);
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
return new HashSet<>(edges.get(vertex).keySet());
}
@Override
protected W getWeightImpl(V vertex1, V vertex2) {
return edges.get(vertex1).get(vertex2);
}
@Override
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;
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
Collection<V> ancestors = new HashSet<>();
edges.forEach((v, adj) -> {
if (adj.containsKey(vertex))
ancestors.add(v);
});
return ancestors;
}
@Override
protected void removeEdgeImpl(V vertex1, V vertex2) {
edges.get(vertex1).remove(vertex2);
public void removeAll() {
edges.clear();
}
@Override
protected void removeAllOutEdgeImpl(V vertex) {
edges.put(vertex, new HashMap<>());
}
@Override
protected void removeAllInEdgeImpl(V vertex) {
edges.forEach((v, map) -> map.remove(vertex));
}
@Override
public int size() {
return edges.size();

View File

@@ -1,7 +1,7 @@
package berack96.lib.graph.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.GraphDirected;
import java.util.*;
@@ -9,13 +9,12 @@ 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> {
public class MatrixGraph<V> extends GraphDirected<V> {
final Map<V, Integer> map = new HashMap<>();
final List<List<W>> matrix = new ArrayList<>();
private final Map<V, Integer> map = new HashMap<>();
private int[][] matrix = new int[0][0];
@Override
public Iterator<V> iterator() {
@@ -23,110 +22,175 @@ public class MatrixGraph<V, W extends Number> extends AGraph<V, W> {
}
@Override
protected Graph<V, W> getNewInstance() {
protected Graph<V> getNewInstance() {
return new MatrixGraph<>();
}
@Override
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);
public void add(V vertex) {
check(vertex);
if (map.containsKey(vertex))
removeAllEdge(vertex);
else {
map.put(vertex, map.size());
matrix = modifyMatrix(map.size());
}
}
@Override
protected boolean containsVertex(V vertex) {
public boolean contains(V vertex) {
check(vertex);
return map.containsKey(vertex);
}
@Override
protected void removeVertex(V vertex) {
public void remove(V vertex) {
checkVert(vertex);
int x = map.remove(vertex);
map.replaceAll((vert, index) -> index>x? index-1:index);
int newSize = map.size();
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);
});
int[][] newMatrix = new int[newSize][newSize];
for (int i = 0; i < newSize; i++)
for (int j = 0; j < newSize; j++) {
int indexI = i + (i < x ? 0 : 1);
int indexJ = j + (j < x ? 0 : 1);
newMatrix[i][j] = matrix[indexI][indexJ];
}
matrix = newMatrix;
map.replaceAll((vert, index) -> index > x ? index - 1 : index);
}
@Override
protected void removeAllVertices() {
public int addEdge(V vertex1, V vertex2, int weight) {
checkVert(vertex1, vertex2);
int i = map.get(vertex1);
int j = map.get(vertex2);
int old = matrix[i][j];
matrix[i][j] = weight;
return old;
}
@Override
public int getWeight(V vertex1, V vertex2) {
checkVert(vertex1, vertex2);
return matrix[map.get(vertex1)][map.get(vertex2)];
}
@Override
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int x = map.get(vertex);
Collection<V> children = new HashSet<>();
Map<Integer, V> invert = getInverted();
for (int i = 0; i < matrix.length; i++)
if (matrix[x][i] != NO_EDGE)
children.add(invert.get(i));
return children;
}
@Override
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int x = map.get(vertex);
Collection<V> ancestors = new HashSet<>();
Map<Integer, V> invert = getInverted();
for (int i = 0; i < matrix.length; i++)
if (matrix[i][x] != NO_EDGE)
ancestors.add(invert.get(i));
return ancestors;
}
/**
* From here on there are some optimization for the methods of the generic DirectedGraph
**/
@Override
public int size() {
return map.size();
}
@Override
public int numberOfEdges() {
int sum = 0;
for (int[] adj : matrix)
for (int edge : adj)
if (edge != NO_EDGE)
sum++;
return sum;
}
@Override
public int degreeIn(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int degree = 0, x = map.get(vertex);
for (int[] ints : matrix) degree += ints[x] == NO_EDGE ? 0 : 1;
return degree;
}
@Override
public int degreeOut(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int degree = 0, x = map.get(vertex);
for (int ints : matrix[x]) degree += ints == NO_EDGE ? 0 : 1;
return degree;
}
@Override
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int x = map.get(vertex);
Arrays.fill(matrix[x], NO_EDGE);
for (int[] ints : matrix) ints[x] = NO_EDGE;
}
@Override
public void removeAllEdge() {
for (int[] ints : matrix)
Arrays.fill(ints, NO_EDGE);
}
@Override
public void removeAll() {
map.clear();
matrix.clear();
matrix = new int[0][0];
}
@Override
protected boolean containsEdgeImpl(V vertex1, V vertex2) {
try {
return matrix.get(map.get(vertex1)).get(map.get(vertex2)) != null;
} catch (Exception ignore) {
return false;
}
public void addAll(Collection<V> vertices) throws NullPointerException {
check(vertices);
for (V vert : vertices)
if (vert != null)
map.compute(vert, (v, i) -> {
if (i == null)
return map.size();
removeAllEdge(vert);
return i;
});
matrix = modifyMatrix(map.size());
}
@Override
protected W addEdgeImpl(V vertex1, V vertex2, W weight) {
return matrix.get(map.get(vertex1)).set(map.get(vertex2), weight);
private int[][] modifyMatrix(int newSize) {
int oldSize = matrix.length;
if (newSize <= oldSize)
return matrix;
int[][] newMatrix = new int[newSize][newSize];
for (int[] ints : newMatrix)
Arrays.fill(ints, NO_EDGE);
for (int i = 0; i < oldSize; i++)
System.arraycopy(matrix[i], 0, newMatrix[i], 0, oldSize);
return newMatrix;
}
@Override
protected W getWeightImpl(V vertex1, V vertex2) {
return matrix.get(map.get(vertex1)).get(map.get(vertex2));
}
@Override
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
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
protected void removeEdgeImpl(V vertex1, V vertex2) {
matrix.get(map.get(vertex1)).set(map.get(vertex2), null);
}
@Override
protected void removeAllOutEdgeImpl(V vertex) {
matrix.get(map.get(vertex)).replaceAll(var -> null);
}
@Override
protected void removeAllInEdgeImpl(V vertex) {
int x = map.get(vertex);
matrix.forEach(list -> list.set(x, null));
private Map<Integer, V> getInverted() {
Map<Integer, V> invert = new HashMap<>(map.size() + 1, 1);
map.forEach((v, i) -> invert.put(i, v));
return invert;
}
}

View File

@@ -0,0 +1,176 @@
package berack96.lib.graph.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.GraphUndirected;
import java.util.*;
public class MatrixUndGraph<V> extends GraphUndirected<V> {
Map<V, Integer> map = new HashMap<>();
private int[][] matrix = new int[0][0];
@Override
protected Graph<V> getNewInstance() {
return new MatrixUndGraph<>();
}
@Override
public boolean contains(V vertex) throws NullPointerException {
check(vertex);
return map.containsKey(vertex);
}
@Override
public void add(V vertex) throws NullPointerException {
check(vertex);
if (map.containsKey(vertex))
removeAllEdge(vertex);
else {
map.put(vertex, map.size());
matrix = modifyMatrix(map.size());
}
}
@Override
public void remove(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int x = map.remove(vertex);
int newSize = map.size();
int[][] newMatrix = new int[newSize][];
for (int i = 0; i < newSize; i++)
newMatrix[i] = i < x ? matrix[i] : new int[i];
for (int i = x; i < newSize; i++)
for (int j = 0; j < newMatrix[i].length; j++)
newMatrix[i][j] = matrix[i + 1][j + (j < x ? 0 : 1)];
matrix = newMatrix;
map.replaceAll((vert, index) -> index > x ? index - 1 : index);
}
@Override
public int getWeight(V vertex1, V vertex2) throws NullPointerException, IllegalArgumentException {
checkVert(vertex1, vertex2);
int x = map.get(vertex1);
int y = map.get(vertex2);
return x == y ? 0 : matrix[Math.max(x, y)][Math.min(x, y)];
}
@Override
public int addEdge(V vertex1, V vertex2, int weight) throws NullPointerException, IllegalArgumentException {
checkVert(vertex1, vertex2);
int x = map.get(vertex1);
int y = map.get(vertex2);
int max = Math.max(x, y);
int min = Math.min(x, y);
int old = matrix[max][min];
matrix[max][min] = weight;
return old;
}
@Override
public Collection<V> getChildren(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
Collection<V> collection = new HashSet<>();
Map<Integer, V> inverted = getInverted();
int x = map.get(vertex);
for (int i = 0; i < matrix.length; i++)
if (i < x && matrix[x][i] != 0)
collection.add(inverted.get(i));
else if (i > x && matrix[i][x] != 0)
collection.add(inverted.get(i));
return collection;
}
@Override
public Collection<V> getAncestors(V vertex) throws NullPointerException, IllegalArgumentException {
return getChildren(vertex);
}
@Override
public Collection<Edge<V>> edges() {
Map<Integer, V> inverted = getInverted();
Collection<Edge<V>> edges = new LinkedList<>();
for (int i = 0; i < matrix.length; i++)
for (int j = 0; j < matrix[i].length; j++)
if (matrix[i][j] != NO_EDGE)
edges.add(new Edge<>(inverted.get(i), inverted.get(j), matrix[i][j]));
return edges;
}
@Override
public int degree(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int x = map.get(vertex);
int degree = 0;
for (int i = 0; i < x; i++)
if (matrix[x][i] != NO_EDGE)
degree++;
for (int i = x; i < matrix.length; i++)
if (matrix[i][x] != NO_EDGE)
degree++;
return degree;
}
@Override
public int size() {
return map.size();
}
@Override
public int numberOfEdges() {
int num = 0;
for (int[] ints : matrix)
for (int edge : ints)
if (edge != NO_EDGE)
num++;
return num;
}
@Override
public Iterator<V> iterator() {
return map.keySet().iterator();
}
@Override
public void removeAllEdge(V vertex) throws NullPointerException, IllegalArgumentException {
checkVert(vertex);
int x = map.get(vertex);
Arrays.fill(matrix[x], NO_EDGE);
for (int i = x + 1; i < matrix.length; i++)
matrix[i][x] = NO_EDGE;
}
@Override
public void removeAllEdge() {
for (int[] adj : matrix)
Arrays.fill(adj, NO_EDGE);
}
private int[][] modifyMatrix(int newSize) {
int oldSize = matrix.length;
if (newSize <= oldSize)
return matrix;
int[][] newMatrix = new int[newSize][];
System.arraycopy(matrix, 0, newMatrix, 0, oldSize);
for (int i = oldSize; i < newSize; i++) {
newMatrix[i] = new int[i];
Arrays.fill(newMatrix[i], NO_EDGE);
}
return newMatrix;
}
private Map<Integer, V> getInverted() {
Map<Integer, V> invert = new HashMap<>(map.size() + 1, 1);
map.forEach((v, i) -> invert.put(i, v));
return invert;
}
}

View File

@@ -2,18 +2,17 @@ package berack96.lib.graph.models;
/**
* Support class used for saving a Graph in a file.
*
* @author Berack96
*
* @author Berack96
*/
public class EdgeSaveStructure {
protected EdgeSaveStructure(String s, String d, String w) {
this.src = s;
this.dest = d;
this.weight = w;
}
public String src;
public String dest;
public String weight;
protected EdgeSaveStructure(String s, String d, int w) {
this.src = s;
this.dest = d;
this.weight = w;
}
public String src;
public String dest;
public int weight;
}

View File

@@ -9,53 +9,54 @@ 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.
*
* @author Berack96
*
* @author Berack96
*/
public class GraphSaveStructure<V, W extends Number> {
final public Gson gson = new Gson();
public class GraphSaveStructure<V> {
final static public Gson gson = new Gson();
public String[] vertices;
public EdgeSaveStructure[] edges;
//public MarkSaveStructure[] marks;
/*
/**
* Load the graph saved in this class in an instance of a graph passed.
* Before loading the graph, it is emptied.
*
* @param graph the graph where insert the data
* @param fileName the file path and name
* @param classV the class of the vertices
* @throws FileNotFoundException in the case the file is not found
* @throws NullPointerException in the case the graph is null
*/
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();
public final void load(@SuppressWarnings("ConstantConditions") Graph<V> graph, String fileName, Class<V> classV) throws FileNotFoundException, NullPointerException {
//this way i use this class for the load
InstanceCreator<GraphSaveStructure<V>> creator = type -> this;
Gson gson = new GsonBuilder().registerTypeAdapter(this.getClass(), creator).create();
JsonReader reader = new JsonReader(new FileReader(fileName));
gson.fromJson(reader, this.getClass());
loadGraph(graph, classV, classW);
gson.fromJson(reader, GraphSaveStructure.class);
loadGraph(graph, classV);
}
/**
* This method can be used by sub-classes for saving other stuff from the graph
*
* @param graph the graph to load with
* @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
* @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 {
protected void loadGraph(Graph<V> graph, Class<V> classV) throws NullPointerException, JsonSyntaxException {
graph.removeAll();
for(String str : vertices)
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)
);
graph.addEdge(gson.fromJson(edge.src, classV), gson.fromJson(edge.dest, classV), edge.weight);
}
/**
* 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>
@@ -68,46 +69,37 @@ public class GraphSaveStructure<V, W extends Number> {
* @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);
public final void save(Graph<V> 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);
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();
}
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) {
protected void saveGraph(Graph<V> graph) {
this.vertices = new String[graph.size()];
int i = 0;
for(Object o: graph.vertices())
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; }
for (Edge<V> edge : graph.edges())
this.edges[i++] = new EdgeSaveStructure(gson.toJson(edge.getSource()), gson.toJson(edge.getDestination()), edge.getWeight());
}
}

View File

@@ -0,0 +1,76 @@
package berack96.lib.graph.struct;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
/**
* Simple implementation of the {@link UnionFind} interface with priority to the find function.
*
* @param <X> the elements to search and merge
*/
public class QuickFind<X> implements UnionFind<X> {
Map<X, Collection<X>> struct = new HashMap<>();
@Override
public int size() {
return struct.size();
}
@Override
public void makeSetAll(Collection<X> elements) throws NullPointerException {
Map<X, Collection<X>> temp = new HashMap<>(elements.size() + 1, 1);
for (X elem : elements)
temp.computeIfAbsent(elem, new AddElement());
struct.putAll(temp);
}
@Override
public void makeSet(X element) throws NullPointerException {
if (element == null)
throw new NullPointerException();
struct.computeIfAbsent(element, new AddElement());
}
@Override
public boolean union(X element1, X element2) throws NullPointerException, IllegalArgumentException {
element1 = find(element1);
element2 = find(element2);
if (element1 == null || element2 == null)
throw new IllegalArgumentException();
if (element1 == element2)
return false;
return struct.get(element1).addAll(struct.remove(element2));
}
@Override
public X find(X element) throws NullPointerException {
if (element == null)
throw new NullPointerException();
if (struct.containsKey(element))
return element;
AtomicReference<X> toReturn = new AtomicReference<>(null);
struct.forEach((key, collection) -> {
if (collection.contains(element))
toReturn.set(key);
});
return toReturn.get();
}
/**
* Stupid class for implementing the adding of a new element
*/
private class AddElement implements Function<X, Collection<X>> {
@Override
public Collection<X> apply(X x) {
Collection<X> coll = new HashSet<>();
coll.add(x);
return coll;
}
}
}

View File

@@ -0,0 +1,57 @@
package berack96.lib.graph.struct;
import java.util.Collection;
/**
* Basic interface for the UnionFind tree sets
*
* @param <X> the object
* @author Berack96
*/
public interface UnionFind<X> {
/**
* Indicate how many different sets there are.
*
* @return the number of sets
*/
int size();
/**
* It creates the single element set for every element in the collection
*
* @param elements the collection of the elements
* @throws NullPointerException in the case of the set being null
*/
void makeSetAll(Collection<X> elements) throws NullPointerException;
/**
* Creates the single element set for the element
*
* @param element the element to insert
* @throws NullPointerException in the case of a null element
*/
void makeSet(X element) throws NullPointerException;
/**
* Merge the tho elements into a single set.<br>
* In the case that the two elements are in the same set it returns false.
*
* @param element1 an element of a set
* @param element2 an element of another set
* @return true in the case of a successful merge, false otherwise
* @throws NullPointerException in the case of a null element
* @throws IllegalArgumentException in the case of an element not in the sets
*/
boolean union(X element1, X element2) throws NullPointerException, IllegalArgumentException;
/**
* Returns the element representing the set in which the element passed resides.<br>
* In case of an element not found then it's returned null
*
* @param element the element in the set
* @return the representing element of the set found
* @throws NullPointerException in the case of a null element
*/
X find(X element) throws NullPointerException;
}

View File

@@ -14,28 +14,28 @@ import java.io.Serial;
import java.util.List;
import java.util.*;
public class GraphInfo<V, W extends Number> extends JPanel {
public class GraphInfo<V> extends JPanel {
@Serial
@Serial
private static final long serialVersionUID = 1L;
private final Map<String, VisitListener<V>> visits;
public GraphInfo(GraphPanel<V, W> graphPanel, VertexListener<V> vListener, EdgeListener<V, W> eListener, Set<VisitStrategy<V, W>> visits) {
public GraphInfo(GraphPanel<V> graphPanel, VertexListener<V> vListener, EdgeListener<V> eListener, Set<VisitStrategy<V>> visits) {
this.visits = new HashMap<>();
/* ZERO (DESCRIPTION) */
JLabel listenerDescription = new JLabel();
JPanel panelDescription = new JPanel();
panelDescription.setOpaque(false);
panelDescription.add(listenerDescription);
/* FIRST (GRAPH INFO) */
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()));
//JLabel gCyclic = new JLabel(String.valueOf(graphPanel.getGraph().isCyclic()));
List<Component> components = new LinkedList<>();
JLabel selected = new JLabel();
@@ -59,7 +59,7 @@ public class GraphInfo<V, W extends Number> extends JPanel {
});
comboBox.addItem("None");
for(VisitStrategy<V, W> strategy: visits) {
for (VisitStrategy<V> strategy : visits) {
String clazz = strategy.getClass().getSimpleName();
VisitListener<V> visit = new VisitListener<>(graphPanel, strategy);
comboBox.addItem(clazz);
@@ -75,7 +75,7 @@ public class GraphInfo<V, W extends Number> extends JPanel {
components.add(new JLabel("Edge Number: "));
components.add(eNumber);
components.add(new JLabel("Is Cyclic: "));
components.add(gCyclic);
//components.add(gCyclic);
JPanel panelInfo = new JPanel();
panelInfo.setOpaque(false);
@@ -182,21 +182,21 @@ public class GraphInfo<V, W extends Number> extends JPanel {
modVertex.doClick();
graphPanel.addObserver((o, arg) -> {
Graph<V, W> graph = graphPanel.getGraph();
Graph<V> graph = graphPanel.getGraph();
if(arg.equals(graph)) {
vNumber.setText(String.valueOf(graph.size()));
eNumber.setText(String.valueOf(graph.numberOfEdges()));
gCyclic.setText(String.valueOf(graph.isCyclic()));
//gCyclic.setText(String.valueOf(graph.isCyclic()));
/* There should be only one */
for(V v : graph.getMarkedWith("selected")) {
int inE = graph.getEdgesIn(v).size();
int outE = graph.getEdgesOut(v).size();
vEdgesInNumber.setText(String.valueOf(inE));
vEdgesOutNumber.setText(String.valueOf(outE));
vEdgesNumber.setText(String.valueOf(inE + outE));
vVertex.setText(v.toString());
int inE = graph.getAncestors(v).size();
int outE = graph.getChildren(v).size();
vEdgesInNumber.setText(String.valueOf(inE));
vEdgesOutNumber.setText(String.valueOf(outE));
vEdgesNumber.setText(String.valueOf(inE + outE));
vVertex.setText(v.toString());
}
}
});

View File

@@ -1,6 +1,5 @@
package berack96.lib.graph.view;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.impl.MapGraph;
@@ -19,31 +18,29 @@ import java.util.Observer;
import java.util.Set;
@SuppressWarnings({"unchecked", "deprecation"})
public class GraphPanel<V, W extends Number> extends Component {
public class GraphPanel<V> extends Component {
@Serial
@Serial
private static final long serialVersionUID = 1L;
private final GraphicalView<VertexComponent<V>> vertexRender;
private final GraphicalView<EdgeComponent<V, W>> edgeRender;
private final GraphicalView<VertexComponent<V>> vertexRender;
private final GraphicalView<EdgeComponent<V>> edgeRender;
private final Class<V> classV;
private final Class<W> classW;
final Container vertices = new Container();
final Container edges = new Container();
private final Graph<V, W> graph = new MapGraph<>();
private final Graph<V> graph = new MapGraph<>();
private final Set<Observer> observers = new HashSet<>();
private GraphListener old = null;
public GraphPanel(GraphicalView<VertexComponent<V>> vertexRender, GraphicalView<EdgeComponent<V, W>> edgeRender, Class<V> classV, Class<W> classW) {
public GraphPanel(GraphicalView<VertexComponent<V>> vertexRender, GraphicalView<EdgeComponent<V>> edgeRender, Class<V> classV) {
this.vertexRender = vertexRender;
this.edgeRender = edgeRender;
this.classV = classV;
this.classW = classW;
}
public Graph<V, W> getGraph() {
public Graph<V> getGraph() {
return graph;
}
@@ -89,7 +86,8 @@ public class GraphPanel<V, W extends Number> extends Component {
VertexComponent<V> component = getVertexAt(center);
component.vertex.remove();
vertices.remove(component);
} catch (Exception ignore) {}
} catch (Exception ignore) {
}
}
public void moveVertex(VertexComponent<V> vertex, Point destination) {
@@ -97,38 +95,38 @@ public class GraphPanel<V, W extends Number> extends Component {
vertex.setLocation(rectangle.x, rectangle.y);
}
public void addEdge(Edge<V, W> edge) {
VertexComponent<V> vSource = null;
VertexComponent<V> vDest = null;
for (Component comp : vertices.getComponents()) {
VertexComponent<V> temp = (VertexComponent<V>) comp;
V vTemp = temp.vertex.getValue();
if (vSource == null && vTemp.equals(edge.getSource()))
vSource = temp;
if (vDest == null && vTemp.equals(edge.getDestination()))
vDest = temp;
}
addEdge(vSource, vDest, edge.getWeight());
public void addEdge(V source, V destination, int weight) {
VertexComponent<V> vSource = null;
VertexComponent<V> vDest = null;
for (Component comp : vertices.getComponents()) {
VertexComponent<V> temp = (VertexComponent<V>) comp;
V vTemp = temp.vertex.get();
if (vSource == null && vTemp.equals(source))
vSource = temp;
if (vDest == null && vTemp.equals(destination))
vDest = temp;
}
addEdge(vSource, vDest, weight);
}
public void addEdge(VertexComponent<V> source, VertexComponent<V> dest, W weight) {
public void addEdge(VertexComponent<V> source, VertexComponent<V> dest, int weight) {
try {
Point center = new Point(Math.abs(source.getX() - dest.getY()), Math.abs(source.getY() - dest.getY()));
EdgeComponent<V, W> edgeComponent = new EdgeComponent<>(source, dest, weight);
EdgeComponent<V> edgeComponent = new EdgeComponent<>(source, dest, weight);
edgeComponent.setBounds(edgeRender.getBox(edgeComponent, center));
edges.add(edgeComponent);
graph.addEdge(edgeComponent.edge);
} catch (Exception e) {
e.printStackTrace();
e.printStackTrace();
}
}
public void removeEdge(VertexComponent<V> source, VertexComponent<V> dest) {
try {
graph.removeEdge(source.vertex.getValue(), dest.vertex.getValue());
EdgeComponent<V, W> toRemove = null;
graph.removeEdge(source.vertex.get(), dest.vertex.get());
EdgeComponent<V> toRemove = null;
for (Component c : edges.getComponents()) {
EdgeComponent<V, W> edge = (EdgeComponent<V, W>) c;
EdgeComponent<V> edge = (EdgeComponent<V>) c;
if (edge.source.equals(source) && edge.destination.equals(dest))
toRemove = edge;
}
@@ -137,7 +135,7 @@ public class GraphPanel<V, W extends Number> extends Component {
} catch (Exception ignore) {}
}
public void modEdge(VertexComponent<V> source, VertexComponent<V> dest, W weight) {
public void modEdge(VertexComponent<V> source, VertexComponent<V> dest, int weight) {
removeEdge(source, dest);
addEdge(source, dest, weight);
}
@@ -147,9 +145,9 @@ public class GraphPanel<V, W extends Number> extends Component {
return component instanceof VertexComponent ? (VertexComponent<V>) component : null;
}
public EdgeComponent<V, W> getEdgeAt(Point point) {
public EdgeComponent<V> getEdgeAt(Point point) {
Component component = edges.getComponentAt(point);
return component instanceof EdgeComponent ? (EdgeComponent<V, W>) component : null;
return component instanceof EdgeComponent ? (EdgeComponent<V>) component : null;
}
public void addObserver(Observer observer) {
@@ -165,7 +163,7 @@ public class GraphPanel<V, W extends Number> extends Component {
}
public void load(String fileName) throws IOException {
new GraphPointsSave<>(this).load(graph, fileName, classV, classW);
new GraphPointsSave<>(this).load(graph, fileName, classV);
}
@Override
@@ -180,24 +178,23 @@ public class GraphPanel<V, W extends Number> extends Component {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Collection<EdgeComponent<V, W>> toRemove = new HashSet<>();
Collection<EdgeComponent<V>> toRemove = new HashSet<>();
for (Component component : edges.getComponents()) {
EdgeComponent<V, W> edge = (EdgeComponent<V, W>) component;
EdgeComponent<V> edge = (EdgeComponent<V>) component;
Vertex<V> source = edge.source.vertex;
Vertex<V> dest = edge.destination.vertex;
if (source.isStillContained() && dest.isStillContained() && graph.containsEdge(source.getValue(), dest.getValue())) {
if (source.isStillContained() && dest.isStillContained() && graph.containsEdge(source.get(), dest.get())) {
Point center = new Point(edge.getX() + edge.getWidth() / 2, edge.getY() + edge.getHeight() / 2);
edge.setBounds(edgeRender.getBox(edge, center));
edgeRender.paint((Graphics2D) g2.create(), edge, center);
}
else
} else
toRemove.add(edge);
}
toRemove.forEach(edges::remove);
for (Component component : vertices.getComponents()) {
VertexComponent<V> vertex = (VertexComponent<V>) component;
if (graph.contains(vertex.vertex.getValue())) {
if (graph.contains(vertex.vertex.get())) {
Point center = new Point(vertex.getX() + vertex.getWidth() / 2, vertex.getY() + vertex.getHeight() / 2);
vertexRender.paint((Graphics2D) g2.create(), vertex, center);
}

View File

@@ -7,21 +7,21 @@ import java.awt.*;
import java.util.LinkedList;
import java.util.List;
public class GraphPointsSave<V, W extends Number> extends GraphSaveStructure<V, W> {
public class GraphPointsSave<V> extends GraphSaveStructure<V> {
final private GraphPanel<V,W> panel;
final private GraphPanel<V> panel;
public Point[] points;
public GraphPointsSave(GraphPanel<V,W> panel) {
public GraphPointsSave(GraphPanel<V> panel) {
this.panel = panel;
}
@Override
protected void saveGraph(Graph<V, W> graph) {
protected void saveGraph(Graph<V> graph) {
super.saveGraph(graph);
List<Point> p = new LinkedList<>();
for(Component vertex : panel.vertices.getComponents()) {
for (Component vertex : panel.vertices.getComponents()) {
Point temp = new Point(vertex.getX(), vertex.getY());
temp.x += vertex.getWidth() / 2;
temp.y += vertex.getHeight() / 2;
@@ -35,20 +35,21 @@ public class GraphPointsSave<V, W extends Number> extends GraphSaveStructure<V,
}
@Override
public void loadGraph(Graph<V, W> graph, Class<V> classV, Class<W> classW) {
super.loadGraph(graph, classV, classW);
public void loadGraph(Graph<V> graph, Class<V> classV) {
super.loadGraph(graph, classV);
panel.vertices.removeAll();
panel.edges.removeAll();
for(int i = 0; i<vertices.length; i++) {
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);
for (String v : vertices) {
V src = gson.fromJson(v, classV);
graph.getChildren(src).forEach(child -> panel.addEdge(src, child, graph.getWeight(src, child)));
}
panel.repaint();
}
}

View File

@@ -19,25 +19,25 @@ import java.util.Set;
*
* @author Berack96
*/
public class GraphWindow<V, W extends Number> extends JFrame {
public class GraphWindow<V> extends JFrame {
@Serial
@Serial
private static final long serialVersionUID = 1L;
private final GraphPanel<V, W> graphPanel;
private final GraphPanel<V> graphPanel;
public GraphWindow(GraphPanel<V, W> graphPanel, VertexListener<V> vListener, EdgeListener<V, W> eListener) {
public GraphWindow(GraphPanel<V> graphPanel, VertexListener<V> vListener, EdgeListener<V> eListener) {
this.setTitle("Grafo");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
Set<VisitStrategy<V, W>> strats = new LinkedHashSet<>();
Set<VisitStrategy<V>> strats = new LinkedHashSet<>();
strats.add(new DFS<>());
strats.add(new BFS<>());
strats.add(new Dijkstra<>());
strats.add(new Tarjan<>());
GraphInfo<V, W> infoPanel = new GraphInfo<>(graphPanel, vListener, eListener, strats);
GraphInfo<V> infoPanel = new GraphInfo<>(graphPanel, vListener, eListener, strats);
this.graphPanel = graphPanel;
this.add(infoPanel, BorderLayout.EAST);
this.add(graphPanel);
@@ -47,7 +47,7 @@ public class GraphWindow<V, W extends Number> extends JFrame {
VisitListener.changeRefresh(millis);
}
public GraphPanel<V, W> getGraphPanel() {
public GraphPanel<V> getGraphPanel() {
return graphPanel;
}
}

View File

@@ -1,25 +1,23 @@
package berack96.lib.graph.view;
import java.awt.Dimension;
import java.awt.Toolkit;
import berack96.lib.graph.view.edge.EdgeIntListener;
import berack96.lib.graph.view.edge.EdgeView;
import berack96.lib.graph.view.vertex.VertexIntListener;
import berack96.lib.graph.view.vertex.VertexView;
import java.awt.*;
public class Main {
public static void main(String[] args) {
GraphPanel<Integer> panel = new GraphPanel<>(new VertexView<>(), new EdgeView<>(), Integer.class);
GraphWindow<Integer> win = new GraphWindow<>(panel, new VertexIntListener(panel), new EdgeIntListener<>(panel));
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // full screen
dim.setSize(dim.width / 2, dim.height / 2);
win.setSize(dim);
win.setLocationRelativeTo(null); //centered
win.visitRefresh(500);
public static void main(String[] args) {
GraphPanel<Integer, Integer> panel = new GraphPanel<>(new VertexView<>(), new EdgeView<>(), Integer.class, Integer.class);
GraphWindow<Integer, Integer> win = new GraphWindow<>(panel, new VertexIntListener(panel), new EdgeIntListener<>(panel));
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // full screen
dim.setSize(dim.width / 2, dim.height / 2);
win.setSize(dim);
win.setLocationRelativeTo(null); //centered
win.visitRefresh(500);
win.setVisible(true);
}
win.setVisible(true);
}
}

View File

@@ -14,13 +14,13 @@ import java.util.concurrent.atomic.AtomicInteger;
public class VisitListener<V> implements GraphListener {
private final GraphPanel<V, ?> panel;
private final VisitStrategy<V, ?> strategy;
private final GraphPanel<V> panel;
private final VisitStrategy<V> strategy;
private final Set<Timer> timers = new HashSet<>();
private static int refreshTime = 1000;
public VisitListener(GraphPanel<V, ?> panel, VisitStrategy<V, ?> strategy) {
public VisitListener(GraphPanel<V> panel, VisitStrategy<V> strategy) {
this.panel = panel;
this.strategy = strategy;
}
@@ -46,8 +46,8 @@ public class VisitListener<V> implements GraphListener {
@Override
public void mousePressed(MouseEvent e) {
this.remove();
Graph<V, ?> graph = panel.getGraph();
Graph<V> graph = panel.getGraph();
graph.unMarkAll();
panel.repaint();

View File

@@ -4,19 +4,21 @@ import berack96.lib.graph.Edge;
import berack96.lib.graph.view.vertex.VertexComponent;
import java.awt.*;
import java.io.Serial;
public class EdgeComponent<V, W extends Number> extends Component {
private static final long serialVersionUID = 1L;
public final VertexComponent<V> source;
public class EdgeComponent<V> extends Component {
@Serial
private static final long serialVersionUID = 1L;
public final VertexComponent<V> source;
public final VertexComponent<V> destination;
public final W weight;
public final Edge<V, W> edge;
public final int weight;
public final Edge<V> edge;
public EdgeComponent(VertexComponent<V> source, VertexComponent<V> destination, W weight) {
public EdgeComponent(VertexComponent<V> source, VertexComponent<V> destination, int weight) {
this.source = source;
this.destination = destination;
this.weight = weight;
this.edge = new Edge<>(source.vertex.getValue(), destination.vertex.getValue(), weight);
this.edge = new Edge<>(source.vertex.get(), destination.vertex.get(), weight);
}
}

View File

@@ -3,22 +3,23 @@ package berack96.lib.graph.view.edge;
import berack96.lib.graph.Vertex;
import berack96.lib.graph.view.GraphPanel;
public class EdgeIntListener<V> extends EdgeListener<V, Integer> {
public class EdgeIntListener<V> extends EdgeListener<V> {
public EdgeIntListener(GraphPanel<V, Integer> graphPanel) {
public EdgeIntListener(GraphPanel<V> graphPanel) {
super(graphPanel);
}
@Override
public void remove() {}
public void remove() {
}
@Override
protected Integer buildNewEdge(Vertex<V> vertex, Vertex<V> vertex1) {
protected int buildNewEdge(Vertex<V> vertex, Vertex<V> vertex1) {
return (int) (Math.random() * 100);
}
@Override
protected Integer buildEdgeFrom(String string) {
protected int buildEdgeFrom(String string) {
return Integer.parseInt(string.replaceAll("[^0-9]+", ""));
}
}

View File

@@ -9,21 +9,21 @@ import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.concurrent.atomic.AtomicReference;
public abstract class EdgeListener<V, W extends Number> implements GraphListener {
public abstract class EdgeListener<V> implements GraphListener {
private final GraphPanel<V, W> graphPanel;
private final GraphPanel<V> graphPanel;
private final AtomicReference<VertexComponent<V>> componentPressed = new AtomicReference<>();
private final AtomicReference<Integer> buttonPressed = new AtomicReference<>();
private final AtomicReference<EdgeComponent<V, W>> edge = new AtomicReference<>();
private final AtomicReference<EdgeComponent<V>> edge = new AtomicReference<>();
private final StringBuilder string = new StringBuilder();
public EdgeListener(GraphPanel<V, W> graphPanel) {
public EdgeListener(GraphPanel<V> graphPanel) {
this.graphPanel = graphPanel;
}
protected abstract W buildNewEdge(Vertex<V> vertex, Vertex<V> vertex1);
protected abstract int buildNewEdge(Vertex<V> vertex, Vertex<V> vertex1);
protected abstract W buildEdgeFrom(String string);
protected abstract int buildEdgeFrom(String string);
@Override
public String getDescription() {
@@ -54,8 +54,8 @@ public abstract class EdgeListener<V, W extends Number> implements GraphListener
VertexComponent<V> source = componentPressed.get();
VertexComponent<V> destination = graphPanel.getVertexAt(e.getPoint());
if (!graphPanel.getGraph().containsEdge(source.vertex.getValue(), destination.vertex.getValue())
&& !source.vertex.equals(destination.vertex))
if (!graphPanel.getGraph().containsEdge(source.vertex.get(), destination.vertex.get())
&& !source.vertex.equals(destination.vertex))
graphPanel.addEdge(source, destination, buildNewEdge(source.vertex, destination.vertex));
} catch (Exception ignore) {
}

View File

@@ -1,18 +1,18 @@
package berack96.lib.graph.view.edge;
import berack96.lib.graph.view.GraphicalView;
import berack96.lib.graph.view.stuff.Arrow;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.Collection;
import berack96.lib.graph.view.GraphicalView;
import berack96.lib.graph.view.stuff.Arrow;
public class EdgeView<V, W extends Number> implements GraphicalView<EdgeComponent<V, W>> {
public class EdgeView<V> implements GraphicalView<EdgeComponent<V>> {
private static final Font FONT = new Font("Papyrus", Font.BOLD, 14);
@Override
public Rectangle getBox(EdgeComponent<V, W> edge, Point center) {
public Rectangle getBox(EdgeComponent<V> edge, Point center) {
/* CALCULATING BOUNDS AND ARROW STARTING AND ENDING POINTS */
Point srcLoc = edge.source.getLocation();
Point desLoc = edge.destination.getLocation();
@@ -29,7 +29,7 @@ public class EdgeView<V, W extends Number> implements GraphicalView<EdgeComponen
/* CALCULATING THE NUMBER SPACE */
int boxDistance = (int) (srcLoc.distance(desLoc) / 2.7);
FontMetrics metrics = edge.getFontMetrics(FONT);
int dimString = metrics.stringWidth(edge.weight.toString());
int dimString = metrics.stringWidth(String.valueOf(edge.weight));
int dimRect = Math.max(dimString, metrics.getHeight());
return new Rectangle(
(int) ((desLoc.x - (vector.x * boxDistance)) - (dimRect / 2)),
@@ -38,7 +38,7 @@ public class EdgeView<V, W extends Number> implements GraphicalView<EdgeComponen
}
@Override
public void paint(Graphics2D g2, EdgeComponent<V, W> edge, Point center) {
public void paint(Graphics2D g2, EdgeComponent<V> edge, Point center) {
/* CALCULATING BOUNDS AND ARROW STARTING AND ENDING POINTS */
Point srcLoc = edge.source.getLocation();
Point desLoc = edge.destination.getLocation();
@@ -55,7 +55,7 @@ public class EdgeView<V, W extends Number> implements GraphicalView<EdgeComponen
/* CALCULATING THE NUMBER SPACE */
int boxDistance = (int) (srcLoc.distance(desLoc) / 2.7);
FontMetrics metrics = edge.getFontMetrics(FONT);
int dimString = metrics.stringWidth(edge.weight.toString());
int dimString = metrics.stringWidth(String.valueOf(edge.weight));
int dimRect = Math.max(dimString, metrics.getHeight());
Rectangle integerRect = new Rectangle(
(int) ((desLoc.x - (vector.x * boxDistance)) - (dimRect / 2)),
@@ -69,8 +69,8 @@ public class EdgeView<V, W extends Number> implements GraphicalView<EdgeComponen
/* THE COLOR OF THE ARROW */
Collection<Object> marksD = edge.destination.vertex.getMarks();
Collection<Object> marksS = edge.source.vertex.getMarks();
boolean isChild = marksD.contains(edge.source.vertex.getValue());
boolean isChild = marksD.contains(edge.source.vertex.get());
boolean selected = marksS.contains("selected");
boolean isMod = marksD.contains("modD") && marksS.contains("modS");
@@ -92,7 +92,7 @@ public class EdgeView<V, W extends Number> implements GraphicalView<EdgeComponen
g2.setColor(arrowColor);
g2.draw(integerRect);
g2.setColor(stringColor);
g2.drawString(edge.weight.toString(), (float) (integerRect.x + (dimRect - dimString) / 2), (float) (integerRect.y + (dimRect + metrics.getHeight() / 2) / 2));
g2.drawString(String.valueOf(edge.weight), (float) (integerRect.x + (dimRect - dimString) / 2), (float) (integerRect.y + (dimRect + metrics.getHeight() / 2) / 2));
}
private Point.Double getVector(Point a, Point b) {

View File

@@ -1,6 +1,7 @@
package berack96.lib.graph.view.stuff;
import java.awt.*;
import java.io.Serial;
/**
* Class that create a Polygon that has a shape of an arrow
@@ -8,9 +9,10 @@ import java.awt.*;
* @author Berack96
*/
public class Arrow extends Polygon {
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
/**
/**
* Create an arrow
*
* @param start the starting point of your arrow (the base)

View File

@@ -7,18 +7,18 @@ import java.util.Arrays;
public class VertexIntListener extends VertexListener<Integer> {
public VertexIntListener(GraphPanel<Integer, ?> panel) {
public VertexIntListener(GraphPanel<Integer> panel) {
super(panel);
}
@Override
public void remove() {}
@Override
protected Integer buildNewVertex(Graph<Integer, ?> graph) {
int counter = 0;
Integer[] vertices = graph.vertices().toArray(new Integer[graph.size()]);
Arrays.sort(vertices);
protected Integer buildNewVertex(Graph<Integer> graph) {
int counter = 0;
Integer[] vertices = graph.vertices().toArray(new Integer[graph.size()]);
Arrays.sort(vertices);
for (Integer vertex : vertices) {
if (!vertex.equals(counter))

View File

@@ -10,14 +10,14 @@ import java.util.concurrent.atomic.AtomicReference;
public abstract class VertexListener<V> implements GraphListener {
protected final GraphPanel<V, ?> panel;
protected final GraphPanel<V> panel;
private final AtomicReference<VertexComponent<V>> componentPressed = new AtomicReference<>();
public VertexListener(GraphPanel<V, ?> panel) {
public VertexListener(GraphPanel<V> panel) {
this.panel = panel;
}
protected abstract V buildNewVertex(Graph<V, ?> graph);
protected abstract V buildNewVertex(Graph<V> graph);
@Override
public String getDescription() {

View File

@@ -12,7 +12,7 @@ public class VertexView<V> implements GraphicalView<VertexComponent<V>> {
@Override
public Rectangle getBox(VertexComponent<V> obj, Point center) {
FontMetrics metrics = obj.getFontMetrics(FONT);
int stringPixels = metrics.stringWidth(obj.vertex.getValue().toString());
int stringPixels = metrics.stringWidth(obj.vertex.get().toString());
int size = Math.max(stringPixels, metrics.getHeight()) + 2 * PADDING;
return new Rectangle(center.x - size / 2, center.y - size / 2, size, size);
@@ -23,9 +23,9 @@ 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 stringPixels = metrics.stringWidth(obj.vertex.get().toString());
int size = Math.max(stringPixels, metrics.getHeight()) + 2 * PADDING;
center.x = center.x - size / 2;
@@ -37,6 +37,6 @@ public class VertexView<V> implements GraphicalView<VertexComponent<V>> {
g2.setColor(visited || discovered || selected ? Color.ORANGE : Color.YELLOW);
g2.fillOval(center.x + PADDING / 2, center.y + PADDING / 2, size - PADDING, size - PADDING);
g2.setColor(Color.BLACK);
g2.drawString(obj.vertex.getValue().toString(), center.x + PADDING + (size - 2 * PADDING - stringPixels) / 2, center.y + (size) / 2 + PADDING);
g2.drawString(obj.vertex.get().toString(), center.x + PADDING + (size - 2 * PADDING - stringPixels) / 2, center.y + (size) / 2 + PADDING);
}
}

View File

@@ -1,18 +1,17 @@
package berack96.lib.graph.visit;
import java.util.List;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import java.util.List;
/**
* Interface that is helpful for implements visit that needs to retrieve the distance between a vertex to all the others
*
* @param <V> the vertex
* @param <W> the weight
* @author Berack96
*/
public interface VisitDistSourceDest<V, W extends Number> extends VisitStrategy<V, W> {
public interface VisitDistSourceDest<V> extends VisitStrategy<V> {
/**
* Get the distance from the source to the destination<br>
@@ -25,5 +24,5 @@ public interface VisitDistSourceDest<V, W extends Number> extends VisitStrategy<
* @throws NullPointerException if one of the vertex is null
* @throws IllegalArgumentException if one of the vertex is not contained in the graph
*/
List<Edge<V, W>> distance(Graph<V, W> graph, V source, V destination) throws NullPointerException, IllegalArgumentException;
List<Edge<V>> distance(Graph<V> graph, V source, V destination) throws NullPointerException, IllegalArgumentException;
}

View File

@@ -1,18 +1,17 @@
package berack96.lib.graph.visit;
import berack96.lib.graph.Edge;
import java.util.List;
import java.util.Map;
import berack96.lib.graph.Edge;
/**
* Interface that is helpful for implements visit that needs to retrieve the distance between a vertex to all the others
*
* @param <V> the vertex
* @param <W> the weight
* @author Berack96
*/
public interface VisitDistance<V, W extends Number> extends VisitStrategy<V, W> {
public interface VisitDistance<V> extends VisitStrategy<V> {
/**
* Get the last calculated distance to all the possible destinations<br>
@@ -23,7 +22,7 @@ public interface VisitDistance<V, W extends Number> extends VisitStrategy<V, W>
* @return the last distance
* @throws NullPointerException if the visit is not already been done
*/
Map<V, List<Edge<V, W>>> getLastDistance() throws NullPointerException;
Map<V, List<Edge<V>>> getLastDistance() throws NullPointerException;
/**
* Get the last source vertex of the visit for calculating the destinations.<br>

View File

@@ -0,0 +1,19 @@
package berack96.lib.graph.visit;
import berack96.lib.graph.Edge;
import java.util.Collection;
/**
* @param <V>
*/
public interface VisitMST<V> extends VisitStrategy<V> {
/**
* Return the latest calculated MST.
*
* @return the latest MST
* @throws NullPointerException if there is no last calculated MST
*/
Collection<Edge<V>> getMST();
}

View File

@@ -6,10 +6,9 @@ import java.util.Collection;
* Interface that is helpful for implements visit that needs to retrieve the SCC
*
* @param <V> the vertex
* @param <W> the weight
* @author Berack96
*/
public interface VisitSCC<V, W extends Number> extends VisitStrategy<V, W> {
public interface VisitSCC<V> extends VisitStrategy<V> {
/**
* Return the latest calculated strongly connected components of the graph.

View File

@@ -1,18 +1,18 @@
package berack96.lib.graph.visit;
import java.util.function.Consumer;
import berack96.lib.graph.Graph;
import berack96.lib.graph.GraphDirected;
import berack96.lib.graph.visit.impl.VisitInfo;
import java.util.function.Consumer;
/**
* This class is used for define some strategy for the visit of a graph.
*
* @param <V> The Object that represent a vertex
* @param <W> The Object that represent the edge (more specifically the weight of the edge)
* @author Berack96
*/
public interface VisitStrategy<V, W extends Number> {
public interface VisitStrategy<V> {
/**
* With this the graph will be visited accordingly to the strategy of the visit.<br>
@@ -20,12 +20,25 @@ public interface VisitStrategy<V, W extends Number> {
* If you want to stop the visit of the graph, you just have to throw any exception in the visit function, but be sure to catch it
*
* @param graph the graph to visit
* @param source the source of the visit
* @param source the vertex where the visit starts
* @param visit the function to apply at each vertex when they are visited
* @return an info of the view
* @throws NullPointerException if one of the arguments is null (only the consumers can be null)
* @throws IllegalArgumentException if the source vertex is not in the graph
* @throws NullPointerException if the graph is null
* @throws UnsupportedOperationException in the case that the visit algorithm cannot be applied to the graph
*/
VisitInfo<V> visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException, UnsupportedOperationException;
VisitInfo<V> visit(Graph<V> graph, V source, Consumer<V> visit) throws NullPointerException, UnsupportedOperationException;
/**
* Method used for checking if the graph is Directed.<br>
* It's useful when the algorithm can only be applied to Directed graph.
*
* @param graph the instance of the graph to check
* @return the instance of the graph casted to a {@link GraphDirected}
* @throws UnsupportedOperationException in the case it's not a directed graph
*/
default GraphDirected<V> checkDirected(Graph<V> graph) {
if (graph instanceof GraphDirected)
return (GraphDirected<V>) graph;
throw new UnsupportedOperationException();
}
}

View File

@@ -6,10 +6,9 @@ import java.util.List;
* Interface that is helpful for implements visit that needs to retrieve the topological sort
*
* @param <V> the vertex
* @param <W> the weight
* @author Berack96
*/
public interface VisitTopological<V, W extends Number> extends VisitStrategy<V, W> {
public interface VisitTopological<V> extends VisitStrategy<V> {
/**
* Return the latest calculated Topological sort of the graph.<br>

View File

@@ -11,13 +11,19 @@ import java.util.function.Consumer;
* 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.
*
* @param <V> the vertex of the graph
* @param <W> the weight of the graph
* @author Berack96
*/
public class BFS<V, W extends Number> implements VisitStrategy<V, W> {
public class BFS<V> implements VisitStrategy<V> {
private int maxDepth = -1;
public BFS<V> setMaxDepth(int depth) {
this.maxDepth = depth;
return this;
}
@Override
public VisitInfo<V> visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
public VisitInfo<V> visit(Graph<V> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
VisitInfo<V> info = new VisitInfo<>(source);
final LinkedList<V> toVisitChildren = new LinkedList<>();
@@ -28,8 +34,10 @@ public class BFS<V, W extends Number> implements VisitStrategy<V, W> {
while (!toVisitChildren.isEmpty()) {
V current = toVisitChildren.removeFirst();
if (maxDepth > -1 && info.getDepth(current) >= maxDepth)
break;
for (V child : graph.getChildrens(current))
for (V child : graph.getChildren(current))
if (!info.isDiscovered(child)) {
toVisitChildren.addLast(child);

View File

@@ -12,13 +12,12 @@ import java.util.function.Consumer;
* The algorithm starts at the root node and explores as far as possible along each branch before backtracking.
*
* @param <V> the vertex of the graph
* @param <W> the weight of the graph
* @author Berack96
*/
public class DFS<V, W extends Number> implements VisitStrategy<V, W> {
public class DFS<V> implements VisitStrategy<V> {
@Override
public VisitInfo<V> visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
public VisitInfo<V> visit(Graph<V> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
VisitInfo<V> info = new VisitInfo<>(source);
final Stack<V> toVisit = new Stack<>();
@@ -27,7 +26,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.getChildrens(current).iterator();
Iterator<V> iter = graph.getChildren(current).iterator();
while (iter.hasNext() && !hasChildToVisit) {
V child = iter.next();

View File

@@ -1,53 +0,0 @@
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;
}
}

View File

@@ -1,26 +1,25 @@
package berack96.lib.graph.visit.impl;
import java.util.*;
import java.util.function.Consumer;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.visit.VisitDistance;
import java.util.*;
import java.util.function.Consumer;
/**
* Class that implements the Dijkstra algorithm and uses it for getting all the distance from a source
*
* @param <V> vertex
* @param <W> weight
* @author Berack96
*/
public class Dijkstra<V, W extends Number> implements VisitDistance<V, W> {
public class Dijkstra<V> implements VisitDistance<V> {
private Map<V, List<Edge<V, W>>> distance = null;
private Map<V, List<Edge<V>>> distance = null;
private V source = null;
@Override
public Map<V, List<Edge<V, W>>> getLastDistance() {
public Map<V, List<Edge<V>>> getLastDistance() {
return distance;
}
@@ -30,15 +29,15 @@ public class Dijkstra<V, W extends Number> implements VisitDistance<V, W> {
}
@Override
public VisitInfo<V> visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
public VisitInfo<V> visit(Graph<V> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
VisitInfo<V> info = new VisitInfo<>(source);
Queue<QueueEntry> queue = new PriorityQueue<>();
Map<V, Double> dist = new HashMap<>();
Map<V, Integer> dist = new HashMap<>();
Map<V, V> prev = new HashMap<>();
this.source = source;
dist.put(source, 0.0); // Initialization
queue.add(new QueueEntry(source, 0.0));
dist.put(source, 0); // Initialization
queue.add(new QueueEntry(source, 0));
while (!queue.isEmpty()) { // The main loop
QueueEntry u = queue.poll(); // Remove and return best vertex
@@ -47,11 +46,11 @@ public class Dijkstra<V, W extends Number> implements VisitDistance<V, W> {
if (visit != null)
visit.accept(u.entry);
graph.getEdgesOut(u.entry).forEach((edge) -> {
V child = edge.getDestination();
for (V child : graph.getChildren(u.entry)) {
info.setDiscovered(child);
double alt = dist.get(u.entry) + edge.getWeight().doubleValue();
Double distCurrent = dist.get(child);
int alt = dist.get(u.entry) + graph.getWeight(u.entry, child);
Integer distCurrent = dist.get(child);
if (distCurrent == null || alt < distCurrent) {
dist.put(child, alt);
prev.put(child, u.entry);
@@ -60,17 +59,17 @@ public class Dijkstra<V, W extends Number> implements VisitDistance<V, W> {
queue.remove(current);
queue.add(current);
}
});
}
}
/* Cleaning up the results */
distance = new HashMap<>();
for (V vertex : prev.keySet()) {
List<Edge<V, W>> path = new LinkedList<>();
List<Edge<V>> path = new LinkedList<>();
V child = vertex;
V father = prev.get(child);
do {
Edge<V, W> edge = new Edge<>(father, child, graph.getWeight(father, child));
Edge<V> edge = new Edge<>(father, child, graph.getWeight(father, child));
path.add(0, edge);
info.setParent(father, child);
child = father;
@@ -84,9 +83,9 @@ public class Dijkstra<V, W extends Number> implements VisitDistance<V, W> {
private class QueueEntry implements Comparable<QueueEntry> {
final V entry;
final Double weight;
final int weight;
QueueEntry(V entry, Double weight) {
QueueEntry(V entry, int weight) {
this.entry = entry;
this.weight = weight;
}

View File

@@ -0,0 +1,44 @@
package berack96.lib.graph.visit.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.GraphUndirected;
import berack96.lib.graph.struct.QuickFind;
import berack96.lib.graph.struct.UnionFind;
import berack96.lib.graph.visit.VisitMST;
import java.util.*;
import java.util.function.Consumer;
/**
* Class that implement the algorithm discovered by Kruskal for the minimum spanning forest
* for a given {@link GraphUndirected}
*
* @param <V> The vertex of the graph
*/
public class Kruskal<V> implements VisitMST<V> {
private Collection<Edge<V>> mst;
@Override
public Collection<Edge<V>> getMST() {
return mst;
}
@Override
public VisitInfo<V> visit(Graph<V> graph, V source, Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
UnionFind<V> sets = new QuickFind<>();
sets.makeSetAll(graph.vertices());
List<Edge<V>> edges = new ArrayList<>(graph.edges());
Collections.sort(edges);
mst = new HashSet<>(graph.size(), 1);
Iterator<Edge<V>> iter = edges.iterator();
while (iter.hasNext() && sets.size() > 1) {
Edge<V> edge = iter.next();
if (sets.union(edge.getSource(), edge.getDestination()))
mst.add(edge);
}
return null;
}
}

View File

@@ -0,0 +1,63 @@
package berack96.lib.graph.visit.impl;
import berack96.lib.graph.Edge;
import berack96.lib.graph.Graph;
import berack96.lib.graph.GraphUndirected;
import berack96.lib.graph.visit.VisitMST;
import java.util.Collection;
import java.util.LinkedList;
import java.util.function.Consumer;
/**
* Class that implement the algorithm discovered by Prim for the minimum spanning forest
* for a given {@link GraphUndirected}
*
* @param <V> The vertex of the graph
*/
public class Prim<V> implements VisitMST<V> {
private Collection<Edge<V>> mst;
@Override
public Collection<Edge<V>> getMST() {
return mst;
}
@Override
public VisitInfo<V> visit(Graph<V> graph, V source, Consumer<V> visit) throws NullPointerException, UnsupportedOperationException {
mst = new LinkedList<>();
Collection<V> vertices = graph.vertices();
if (source == null)
source = vertices.iterator().next();
VisitInfo<V> info = new VisitInfo<>(source);
V current = source;
do {
if (current == null)
current = vertices.iterator().next();
Edge<V> min = null;
for (Edge<V> edge : graph.edgesOf(current))
if (vertices.contains(edge.getDestination()))
min = (min == null || edge.getWeight() < min.getWeight() ? edge : min);
info.setParent(source, current);
info.setVisited(current);
if (visit != null)
visit.accept(current);
if (min == null)
current = null;
else {
vertices.remove(current);
source = min.getSource();
current = min.getDestination();
mst.add(min);
}
} while (vertices.size() != 0);
return info;
}
}

View File

@@ -11,10 +11,9 @@ import java.util.function.Consumer;
* Class that implements the Tarjan algorithm and uses it for getting the SCC and the topological sort
*
* @param <V> vertex
* @param <W> weight
* @author Berack96
*/
public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopological<V, W> {
public class Tarjan<V> implements VisitSCC<V>, VisitTopological<V> {
private Collection<Collection<V>> SCC = null;
private List<V> topologicalSort = null;
@@ -44,15 +43,15 @@ public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopolog
* @throws IllegalArgumentException doesn't throw this
*/
@Override
public VisitInfo<V> visit(Graph<V, W> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
public VisitInfo<V> visit(Graph<V> graph, V source, Consumer<V> visit) throws NullPointerException, IllegalArgumentException {
SCC = new HashSet<>();
topologicalSort = new LinkedList<>();
topologicalSort = new ArrayList<>(graph.size());
info = null;
indices = new HashMap<>();
lowLink = new HashMap<>();
stack = new Stack<>();
Integer index = 0;
int index = 0;
for (V vertex : graph) {
if (info == null)
@@ -61,11 +60,11 @@ public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopolog
strongConnect(graph, vertex, index, visit);
}
topologicalSort = (graph.size() == SCC.size()) ? new ArrayList<>(topologicalSort) : null;
topologicalSort = (graph.size() == SCC.size()) ? topologicalSort : null;
return info;
}
private void strongConnect(Graph<V, W> graph, V vertex, Integer index, Consumer<V> visit) {
private void strongConnect(Graph<V> graph, V vertex, Integer index, Consumer<V> visit) {
// Set the depth index for v to the smallest unused index
indices.put(vertex, index);
lowLink.put(vertex, index);
@@ -74,7 +73,7 @@ public class Tarjan<V, W extends Number> implements VisitSCC<V, W>, VisitTopolog
info.setDiscovered(vertex);
// Consider successors of v
for (V child : graph.getChildrens(vertex)) {
for (V child : graph.getChildren(vertex)) {
if (!indices.containsKey(child)) {
info.setParent(vertex, child);
strongConnect(graph, child, index, visit);

View File

@@ -12,9 +12,9 @@ import java.util.function.Consumer;
* @param <V> the vertex of the visit
* @author Berack96
*/
public class VisitInfo<V> {
public class VisitInfo<V> implements Iterable<VisitInfo<V>.VertexInfo> {
private static final int NOT_SET = -1;
private final Map<V, VertexInfo> vertices;
private final V source;
private long time;
@@ -229,11 +229,11 @@ public class VisitInfo<V> {
*
* @param consumer the function to apply to each
*/
public void forEachDiscovered(Consumer<VertexInfo> consumer) {
public void forEachDiscovered(Consumer<? super VertexInfo> consumer) {
Queue<VertexInfo> queue = new PriorityQueue<>();
vertices.forEach((v, info) -> {
if(info.timeDiscovered != NOT_SET)
queue.offer(new VertexInfo(info, false));
vertices.forEach((v, info) -> {
if (info.timeDiscovered != NOT_SET)
queue.offer(new VertexInfo(info, false));
});
while (!queue.isEmpty())
@@ -246,41 +246,35 @@ public class VisitInfo<V> {
*
* @param consumer the function to apply to each
*/
public void forEachVisited(Consumer<VertexInfo> consumer) {
public void forEachVisited(Consumer<? super VertexInfo> consumer) {
Queue<VertexInfo> queue = new PriorityQueue<>();
vertices.forEach((v, info) -> {
if(info.timeVisited != NOT_SET)
queue.offer(new VertexInfo(info, true));
vertices.forEach((v, info) -> {
if (info.timeVisited != NOT_SET)
queue.offer(new VertexInfo(info, true));
});
while (!queue.isEmpty())
consumer.accept(queue.poll());
}
/**
* Iterate through all the vertices discovered and visited with the correct timeline.<br>
* The vertices will be visited in the order that they are discovered and visited, so a vertex can appear two times (one for the discovery, anc the other for the visit)
*
* @param consumer the function to apply at each vertex
*/
public void forEach(Consumer<VertexInfo> consumer) {
Queue<VertexInfo> queue = new PriorityQueue<>();
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));
@Override
public Iterator<VertexInfo> iterator() {
List<VertexInfo> list = new ArrayList<>(vertices.size() * 2);
vertices.forEach((v, info) -> {
if (info.timeDiscovered != NOT_SET)
list.add(new VertexInfo(info, false));
if (info.timeVisited != NOT_SET)
list.add(new VertexInfo(info, true));
});
while (!queue.isEmpty())
consumer.accept(queue.remove());
Collections.sort(list);
return list.iterator();
}
/**
* Class used mainly for storing the data of the visit
*/
public class VertexInfo implements Comparable<VertexInfo> {
public V vertex;
public V vertex;
public V parent;
public long timeDiscovered;
public long timeVisited;

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1,54 @@
{"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"}]}
{
"vertices": [
"\"6\"",
"\"5\"",
"\"4\"",
"\"3\"",
"\"2\"",
"\"1\"",
"\"8\"",
"\"7\""
],
"edges": [
{
"src": "\"4\"",
"dest": "\"6\"",
"weight": 6
},
{
"src": "\"2\"",
"dest": "\"5\"",
"weight": 4
},
{
"src": "\"5\"",
"dest": "\"4\"",
"weight": 5
},
{
"src": "\"5\"",
"dest": "\"3\"",
"weight": 2
},
{
"src": "\"1\"",
"dest": "\"3\"",
"weight": 1
},
{
"src": "\"6\"",
"dest": "\"2\"",
"weight": 2
},
{
"src": "\"1\"",
"dest": "\"2\"",
"weight": 1
},
{
"src": "\"8\"",
"dest": "\"7\"",
"weight": 9
}
]
}