Skip to content
Snippets Groups Projects
Commit 66bd2dbe authored by Sondre.Bolland1's avatar Sondre.Bolland1
Browse files

commit message

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 712 additions and 0 deletions
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
/bin/
bin
/.vscode/
.vscode
tmp
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Binaries
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
*.war
*.ear
*.sar
*.class
# Maven
target/
/target/
# IntelliJ project files
*.iml
*.iws
*.ipr
*.idea/
# Eclipse project files
.settings/
.classpath
.project
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Lab 5 - Undirected Graphs
In this task you will be coding a [graph](https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)) datastructure implementation **Adjacency Set** which is an Adjacency List that uses sets instead of lists.
The graphs in this assignment are **undirected** and **unweighted**:
`Main.java` contains some code to do simple checks for the graph implementation.
### Task 1
Implement the remaining methods in `AdjacencySet.java`. Methods:
* `addNode(V node)`
* `removeNode(V node)`
* `addEdge(V u, v v)`
* `removeEdge(V u, V v)`
* `hasNode(V node)`
✅ Run `AdjacencySetTest` to check your solution. The task is passed if all tests pass.
### Task 2
An essential part of graph theory is to be able to search through a graph. In this task we want to know whether two nodes `u` and `v` are connected.
<img align="center" src="images/Lab5_graph.png" width="400"/>
In the graph above `0` and `2` are connected since there is a direct edge between them. `3` and `2` are also connected since there are nodes inbetween that connect them. <br></br>
While `2` and `5` are not connected since there are noe edges that directly connect them or any inbetween other nodes.
**TODO: Implement `GraphSearch::connected`.**
✅ Run `GraphSearchTest` to check your solution. The task is passed if all tests pass.
images/Lab5_graph.png

12.9 KiB

pom.xml 0 → 100644
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>INF102</groupId>
<artifactId>lab5</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>lab5</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javatuples</groupId>
<artifactId>javatuples</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven
defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
package INF102.lab5.graph;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class AdjacencySet<V> implements IGraph<V> {
private Set<V> nodes;
private Map<V, Set<V>> nodeToNode;
public AdjacencySet() {
nodes = new HashSet<>();
nodeToNode = new HashMap<>();
}
@Override
public int size() {
return nodes.size();
}
@Override
public Set<V> getNodes() {
return Collections.unmodifiableSet(nodes);
}
@Override
public void addNode(V node) {
throw new UnsupportedOperationException("Implement me :)");
}
@Override
public void removeNode(V node) {
throw new UnsupportedOperationException("Implement me :)");
}
@Override
public void addEdge(V u, V v) {
throw new UnsupportedOperationException("Implement me :)");
}
@Override
public void removeEdge(V u, V v) {
throw new UnsupportedOperationException("Implement me :)");
}
@Override
public boolean hasNode(V node) {
throw new UnsupportedOperationException("Implement me :)");
}
@Override
public boolean hasEdge(V u, V v) {
return nodeToNode.get(u).contains(v);
}
@Override
public Set<V> getNeighbourhood(V node) {
return Collections.unmodifiableSet(nodeToNode.get(node));
}
@Override
public String toString() {
StringBuilder build = new StringBuilder();
for (V node : nodeToNode.keySet()) {
Set<V> nodeList = nodeToNode.get(node);
build.append(node);
build.append(" --> ");
build.append(nodeList);
build.append("\n");
}
return build.toString();
}
}
package INF102.lab5.graph;
/**
* This class is used to conduct search algorithms of a graph
*/
public class GraphSearch<V> implements IGraphSearch<V> {
private IGraph<V> graph;
public GraphSearch(IGraph<V> graph) {
this.graph = graph;
}
@Override
public boolean connected(V u, V v) {
throw new UnsupportedOperationException("Implement me :)");
}
}
package INF102.lab5.graph;
import java.util.Set;
public interface IGraph<V> {
/**
* Number of nodes in the graph
* @return number of nodes in graph
*/
public int size();
/**
* Get all nodes in graph
* @return set of graph nodes
*/
public Set<V> getNodes();
/**
* Add <code>node</code> to graph
* @param node
*/
public void addNode(V node);
/**
* Remove <code>node</code> from graph
* @param node
*/
public void removeNode(V node);
/**
* Add edge between node <code>u</code> and <code>v</code>
* @param u
* @param v
* @throws IllegalArgumentException if the nodes given are not in the graph
*/
public void addEdge(V u, V v);
/**
* Remove edge between node <code>u</code> and <code>v</code>
* @param u
* @param v
*/
public void removeEdge(V u, V v);
/**
* Checks if there is a node <code>node</code> in the graph
* @param node
* @return true if node is in graph
*/
public boolean hasNode(V node);
/**
* Checks if there is an edge between node <code>u</code> and <code>v</code>
* @param u
* @param v
* @return true if there is an edge between <code>u</code> and <code>v</code>
*/
public boolean hasEdge(V u, V v);
/**
* Finds all neighbours of node <code>u</code>.
* The neighbours of a node is all nodes which it has an edge to.
* @param node
* @return list of all neighbours
*/
public Set<V> getNeighbourhood(V node);
}
package INF102.lab5.graph;
public interface IGraphSearch<V> {
/**
* Checks if node <code>u</code> and <code>v</code> are connected,
* i.e. is there a path of edges between <code>u</code> and <code>v</code>
* @param u
* @param v
* @return true if connected, false if not
*/
public boolean connected(V u, V v);
}
package INF102.lab5.graph;
public class Main {
public static final int N_NODES = 5;
public static void main(String[] args) {
IGraph<Integer> graph = new AdjacencySet<>();
createGraph(graph);
IGraphSearch<Integer> graphSearch = new GraphSearch<>(graph);
int u = 0;
int v = 2;
System.out.println("----Expected to be True----");
System.out.printf("%-17s| Edge %d and %d connected? %5b%n", graph.getClass().getSimpleName(), u, v, graphSearch.connected(u, v));
v = 4;
System.out.println("\n----Expected to be False----");
System.out.printf("%-17s| Edge %d and %d connected? %5b%n", graph.getClass().getSimpleName(), u, v, graphSearch.connected(u, v));
}
/**
* Creates a simple graph with 5 nodes.
*
* 0 -> 1 -> 2 3 -> 4
*
* @param graph
*/
public static void createGraph(IGraph<Integer> graph) {
graph.addNode(0);
graph.addNode(1);
graph.addNode(2);
graph.addNode(3);
graph.addNode(4);
graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(3, 4);
}
}
package INF102.lab5.graph;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class AdjacencySetTest extends GraphTest {
IGraph<Integer> adjacencySet;
@BeforeEach
public void setup() {
adjacencySet = new AdjacencySet<>();
for (int i = 0; i < N_NODES; i++) {
adjacencySet.addNode(i);
}
}
@Test
public void setAddEdgeToNodeNotInGraph() {
addEdgeToNodeNotInGraph(adjacencySet);
}
@Test
public void setAddEdgeTest() {
addEdgeTest(adjacencySet);
}
@Test
public void setRemoveEdgeTest() {
removeEdgeTest(adjacencySet);
}
@Test
public void setGetNeighbourhoodTest() {
getNeighbourhoodTest(adjacencySet);
}
@Test
public void setAddNodeTest() {
addNodeTest(adjacencySet);
}
@Test
public void setRemoveNodeTest() {
removeNodeTest(adjacencySet);
}
@Test
public void setDuplicateNodeTest() {
duplicateNodeTest(adjacencySet);
}
@Test
public void setRemoveEgdesWithNodeTest(){
removeEgdesWithNodeTest(adjacencySet);
}
}
package INF102.lab5.graph;
import org.junit.jupiter.api.Test;
/**
* An implementation of a graph datastrucutre using adjacency matrix should yield a OutOfMemoryException when the number of nodes
* is too high, while using adjacency list/set should not.
*/
public class GraphImplementationTest {
final int OUT_OF_MEMORY_GRAPH_SIZE = 100000;
@Test
public void listNotOutOfMemoryTest() {
AdjacencySet<Integer> set = new AdjacencySet<Integer>();
for (int i = 0; i < OUT_OF_MEMORY_GRAPH_SIZE; i++) {
set.addNode(i);
}
}
}
package INF102.lab5.graph;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Random;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class GraphSearchTest {
private IGraph<Integer> graph;
private IGraphSearch<Integer> graphSearch;
private final int N_NODES = 1000;
private Random random = new Random();
/**
* Adds edges of all nodes from 0 to N, i.e.:
* (0 -> 1), (1 -> 2), ..., (N-1 -> N)
*
* @param graph
*/
public void createConnectedGraph(IGraph<Integer> graph) {
for (int i = 0; i < N_NODES - 1; i++) {
graph.addEdge(i, i + 1);
}
}
@BeforeEach
public void setup() {
graph = new AdjacencySet<>();
for (int i = 0; i < N_NODES; i++) {
graph.addNode(i);
}
graphSearch = new GraphSearch<>(graph);
}
@Test
public void connectedTest() {
createConnectedGraph(graph);
int u = 0;
int v = N_NODES - 1;
assertTrue(graphSearch.connected(u, v));
}
@Test
public void notConnectedTest() {
createConnectedGraph(graph);
int u = 0;
int v = N_NODES - 1;
int w = N_NODES - 2;
graph.removeEdge(w, v);
assertFalse(graphSearch.connected(u, v));
}
@Test
public void neighbouringNodesAreConnectedTest() {
createConnectedGraph(graph);
for (int i = 0; i < 1000; i++) {
int u = random.nextInt(N_NODES);
int v = random.nextInt(N_NODES);
graph.addEdge(u, v);
assertTrue(graphSearch.connected(u, v));
}
}
@Test
public void connectedUndirectedTest() {
for (int i = 0; i < 1000; i++) {
int u = random.nextInt(N_NODES);
int v = random.nextInt(N_NODES);
graph.addEdge(u, v);
}
for (int i = 0; i < 10000; i++) {
int u = random.nextInt(N_NODES);
int v = random.nextInt(N_NODES);
boolean uConnectedToV = graphSearch.connected(u, v);
boolean vConnectedToU = graphSearch.connected(v, u);
assertEquals(uConnectedToV, vConnectedToU);
}
}
}
package INF102.lab5.graph;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public abstract class GraphTest {
final int N_NODES = 1000;
Random random = new Random();
/**
* Adds edges of all nodes from 0 to N, i.e.:
* (0 -> 1), (1 -> 2), ..., (N-1 -> N)
*
* @param graph
*/
public void createConnectedGraph(IGraph<Integer> graph) {
for (int i = 0; i < N_NODES - 1; i++) {
graph.addEdge(i, i + 1);
}
}
public void addEdgeToNodeNotInGraph(IGraph<Integer> graph) {
int u = N_NODES + 1;
int v = random.nextInt(N_NODES);
assertThrows(IllegalArgumentException.class, () -> graph.addEdge(u, v),
"You can't add an edge to a node that doesn't exist on the graph.");
assertThrows(IllegalArgumentException.class, () -> graph.addEdge(v, u),
"You can't add an edge to a node that doesn't exist on the graph.");
}
public void addEdgeTest(IGraph<Integer> graph) {
int u = 0;
int v = 0;
for (int i = 0; i < N_NODES; i++) {
u = random.nextInt(N_NODES);
v = random.nextInt(N_NODES);
graph.addEdge(u, v);
assertTrue(graph.hasEdge(u, v), "Nodes " + u + " and " + v + " should have an edge between them.");
assertTrue(graph.hasEdge(v, u),
"In an undirected graph " + u + " and " + v + " should have an edge both ways.");
}
}
public void removeEdgeTest(IGraph<Integer> graph) {
for (int i = 0; i < N_NODES; i++) {
int u = random.nextInt(N_NODES);
int v = random.nextInt(N_NODES);
graph.addEdge(u, v);
assertTrue(graph.hasEdge(u, v), "Nodes " + u + " and " + v + " should have an edge between them.");
assertTrue(graph.hasEdge(v, u),
"In an undirected graph " + u + " and " + v + " should have an edge both ways.");
graph.removeEdge(u, v);
assertFalse(graph.hasEdge(u, v), "Nodes " + u + " and " + v + " should not have an edge between them.");
assertFalse(graph.hasEdge(v, u), "Nodes " + v + " and " + u + " should not have an edge between them.");
}
}
public void getNeighbourhoodTest(IGraph<Integer> graph) {
int u = random.nextInt(N_NODES);
Set<Integer> randomNodes = new HashSet<>();
for (int i = 0; i < 100; i++) {
int v = random.nextInt(N_NODES);
graph.addEdge(u, v);
randomNodes.add(v);
}
for (Integer w : graph.getNeighbourhood(u)) {
if (!randomNodes.contains(w))
fail("A neighbour of u was not in the list of neigbhours");
}
}
public void addNodeTest(IGraph<Integer> graph) {
int extraNode = N_NODES + 1;
assertEquals(N_NODES, graph.size(), "Graph should have " + N_NODES + " nodes.");
assertFalse(graph.hasNode(extraNode), "Graph should not have node " + extraNode);
int u = extraNode;
graph.addNode(u);
assertTrue(graph.hasNode(u), "Graph should have node " + u);
assertEquals(extraNode, graph.size(), "Graph should have " + extraNode + " nodes.");
}
public void duplicateNodeTest(IGraph<Integer> graph) {
int node = N_NODES - 2;
graph.addEdge(node, node + 1);
graph.addNode(node);
assertTrue(graph.hasEdge(node, node + 1),
"Trying to add a duplicate node should not remove the egdes from the original node");
}
public void removeNodeTest(IGraph<Integer> graph) {
addNodeTest(graph);
int u = random.nextInt(N_NODES);
assertNotEquals(N_NODES, graph.size(), "Graph should not have " + N_NODES + " nodes.");
graph.removeNode(u);
assertFalse(graph.hasNode(u), "Graph should not have node " + u);
assertEquals(N_NODES, graph.size(), "Graph should have " + N_NODES + " nodes.");
}
public void removeEgdesWithNodeTest(IGraph<Integer> graph) {
int u = random.nextInt(N_NODES);
int v = random.nextInt(N_NODES);
int z = random.nextInt(N_NODES);
graph.addEdge(u, v);
graph.addEdge(u, z);
assertTrue(graph.getNeighbourhood(u).size() >= 1);
assertThrows(NullPointerException.class, () -> {
graph.removeNode(u);
assertTrue(graph.getNeighbourhood(u).size() == 0);
},
"Removing a node should remove the egdes connencting the node");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment