diff --git a/core-java/src/main/java/com/baeldung/graph/Graph.java b/core-java/src/main/java/com/baeldung/graph/Graph.java new file mode 100644 index 0000000000..7095f64709 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/graph/Graph.java @@ -0,0 +1,112 @@ +package com.baeldung.graph; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class Graph { + private Set vertices; + private Set edges; + private Map> adjVertices; + + Graph() { + this.vertices = new HashSet(); + this.edges = new HashSet(); + this.adjVertices = new HashMap>(); + } + + boolean addVertex(String label) { + return vertices.add(new Vertex(label)); + } + + boolean removeVertex(String label) { + return vertices.remove(new Vertex(label)); + } + + boolean addEdge(String label1, String label2) { + Vertex v1 = new Vertex(label1); + Vertex v2 = new Vertex(label2); + Edge e = new Edge(v1, v2); + if (this.edges.add(e)) { + adjVertices.putIfAbsent(v1, new HashSet<>()); + adjVertices.putIfAbsent(v2, new HashSet<>()); + adjVertices.get(v1) + .add(e); + adjVertices.get(v2) + .add(e); + } + return true; + } + + boolean removeEdge(String label1, String label2) { + Vertex v1 = new Vertex(label1); + Vertex v2 = new Vertex(label2); + Edge e = new Edge(v1, v2); + if (this.edges.remove(e)) { + Set eV1 = adjVertices.get(v1); + Set eV2 = adjVertices.get(v2); + + if (eV1 != null) + eV1.remove(e); + if (eV2 != null) + eV2.remove(e); + } + return true; + } + + Set getAdjVertices(String label) { + Vertex v = new Vertex(label); + return adjVertices.get(v) + .stream() + .map(e -> e.v1.equals(v) ? e.v2 : e.v1) + .collect(Collectors.toSet()); + } + + class Vertex { + String label; + Vertex(String label) { + this.label = label; + } + @Override + public boolean equals(Object obj) { + Vertex vertex = (Vertex) obj; + return vertex.label == label; + } + @Override + public int hashCode() { + return label.hashCode(); + } + @Override + public String toString() { + return label; + } + } + + class Edge { + Vertex v1; + Vertex v2; + Edge(String label1, String label2) { + this.v1 = new Vertex(label1); + this.v2 = new Vertex(label2); + } + Edge(Vertex vertex1, Vertex vertex2) { + this.v1 = vertex1; + this.v2 = vertex2; + } + @Override + public boolean equals(Object obj) { + Edge edge = (Edge) obj; + return edge.v1.equals(v1) && edge.v2.equals(v2); + } + @Override + public int hashCode() { + return v1.hashCode() + v2.hashCode(); + } + @Override + public String toString() { + return v1.label + "-" + v2.label; + } + } +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/graph/GraphTraversal.java b/core-java/src/main/java/com/baeldung/graph/GraphTraversal.java new file mode 100644 index 0000000000..479e653a5c --- /dev/null +++ b/core-java/src/main/java/com/baeldung/graph/GraphTraversal.java @@ -0,0 +1,44 @@ +package com.baeldung.graph; + +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; +import java.util.Stack; + +import com.baeldung.graph.Graph.Vertex; + +public class GraphTraversal { + static Set depthFirstTraversal(Graph graph, String root) { + Set visited = new LinkedHashSet(); + Stack stack = new Stack(); + stack.push(root); + while (!stack.isEmpty()) { + String vertex = stack.pop(); + if (!visited.contains(vertex)) { + visited.add(vertex); + for (Vertex v : graph.getAdjVertices(vertex)) { + stack.push(v.label); + } + } + } + return visited; + } + + static Set breadthFirstTraversal(Graph graph, String root) { + Set visited = new LinkedHashSet(); + Queue queue = new LinkedList(); + queue.add(root); + visited.add(root); + while (!queue.isEmpty()) { + String vertex = queue.poll(); + for (Vertex v : graph.getAdjVertices(vertex)) { + if (!visited.contains(v.label)) { + visited.add(v.label); + queue.add(v.label); + } + } + } + return visited; + } +} \ No newline at end of file diff --git a/core-java/src/test/java/com/baeldung/graph/GraphTraversalUnitTest.java b/core-java/src/test/java/com/baeldung/graph/GraphTraversalUnitTest.java new file mode 100644 index 0000000000..84611a580a --- /dev/null +++ b/core-java/src/test/java/com/baeldung/graph/GraphTraversalUnitTest.java @@ -0,0 +1,36 @@ +package com.baeldung.graph; + +import org.junit.Assert; +import org.junit.Test; + +public class GraphTraversalUnitTest { + @Test + public void givenAGraph_whenTraversingDepthFirst_thenExpectedResult() { + Graph graph = createGraph(); + Assert.assertEquals("[A, D, E, B, C]", + GraphTraversal.depthFirstTraversal(graph, "A").toString()); + } + + @Test + public void givenAGraph_whenTraversingBreadthFirst_thenExpectedResult() { + Graph graph = createGraph(); + Assert.assertEquals("[A, B, D, C, E]", + GraphTraversal.breadthFirstTraversal(graph, "A").toString()); + } + + Graph createGraph() { + Graph graph = new Graph(); + graph.addVertex("A"); + graph.addVertex("B"); + graph.addVertex("C"); + graph.addVertex("D"); + graph.addVertex("E"); + graph.addEdge("A", "B"); + graph.addEdge("A", "D"); + graph.addEdge("B", "C"); + graph.addEdge("D", "C"); + graph.addEdge("B", "E"); + graph.addEdge("D", "E"); + return graph; + } +} \ No newline at end of file