* 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
161 lines
3.6 KiB
Java
161 lines
3.6 KiB
Java
package berack96.lib.graph.impl;
|
|
|
|
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
|
|
* @author Berack96
|
|
*/
|
|
public class ListGraph<V> extends GraphDirected<V> {
|
|
|
|
final private Map<V, List<Adj>> adj = new Hashtable<>();
|
|
|
|
@Override
|
|
public Iterator<V> iterator() {
|
|
return adj.keySet().iterator();
|
|
}
|
|
|
|
@Override
|
|
protected Graph<V> getNewInstance() {
|
|
return new ListGraph<>();
|
|
}
|
|
|
|
@Override
|
|
public void add(V vertex) {
|
|
check(vertex);
|
|
if (adj.containsKey(vertex))
|
|
removeAllEdge(vertex);
|
|
else
|
|
adj.put(vertex, new LinkedList<>());
|
|
}
|
|
|
|
@Override
|
|
public boolean contains(V vertex) {
|
|
check(vertex);
|
|
return adj.containsKey(vertex);
|
|
}
|
|
|
|
@Override
|
|
public void remove(V vertex) {
|
|
checkVert(vertex);
|
|
adj.remove(vertex);
|
|
adj.forEach((v, list) -> list.remove(getAdj(list, vertex)));
|
|
}
|
|
|
|
@Override
|
|
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();
|
|
}
|
|
|
|
private Adj getAdj(List<Adj> list, V vertex) {
|
|
for (Adj adj : list)
|
|
if (Objects.equals(adj.vertex, vertex))
|
|
return adj;
|
|
return null;
|
|
}
|
|
|
|
private class Adj {
|
|
private final V vertex;
|
|
private int weight;
|
|
|
|
private Adj(V vertex, int weight) {
|
|
this.vertex = vertex;
|
|
this.weight = weight;
|
|
}
|
|
}
|
|
}
|