forked from rampatra/Algorithms-and-Data-Structures-in-Java
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUndirectedGraph.java
166 lines (152 loc) · 5.68 KB
/
UndirectedGraph.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package com.rampatra.base;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author rampatra
* @since 2019-02-14
*/
public class UndirectedGraph<E extends Comparable<E>> extends Graph<E> {
// map for a fast lookup
private Map<E, GraphNode<E>> nodes = new HashMap<>();
/**
* Adds an edge between a node with value {@code value} and another node with value {@code adjacentValue}. As the
* graph is undirected, the edges are added in both the nodes. If nodes with respective values are not present in
* the graph then this method creates the nodes.
*
* @param value refers to the value for first node
* @param adjacentValue refers to the value for the second node
* @return the node with value {@code value}, or the first node
*/
public GraphNode<E> addEdge(E value, E adjacentValue) {
GraphNode<E> node = nodes.get(value);
GraphNode<E> adjNode = nodes.get(adjacentValue);
if (node == null && value != null) {
node = new GraphNode<>(value);
nodes.put(value, node);
}
if (adjNode == null && adjacentValue != null) {
adjNode = new GraphNode<>(adjacentValue);
nodes.put(adjacentValue, adjNode);
}
if (node != null && adjNode != null) {
node.adjacentNodes.add(adjNode);
adjNode.adjacentNodes.add(node); // as this is an undirected graph
}
return node;
}
/**
* Method to check whether {@code src} and {@code dest} nodes are connected by depth first search (DFS).
*
* @param src source node in graph
* @param dest destination node in graph
* @return {@code true} if there is a path from {@code src} to {@code dest}, {@code false} otherwise
*/
public boolean hasPathDFS(E src, E dest) {
GraphNode<E> s = nodes.get(src);
GraphNode<E> d = nodes.get(dest);
Set<GraphNode<E>> visited = new HashSet<>(); // to save all visited nodes so that we do not visit them again
return hasPathDFS(s, d, visited);
}
private boolean hasPathDFS(GraphNode<E> src, GraphNode<E> dest, Set<GraphNode<E>> visited) {
if (src == null || dest == null) {
return false;
}
if (src.value.compareTo(dest.value) == 0) {
return true;
} else if (!visited.contains(src)) {
visited.add(src);
for (GraphNode<E> node : src.adjacentNodes) {
if (hasPathDFS(node, dest, visited)) {
return true;
}
}
}
return false;
}
/**
* Method to check whether {@code src} and {@code dest} nodes are connected by breadth first search (BFS).
*
* @param src source node in graph
* @param dest destination node in graph
* @return {@code true} if there is a path from {@code src} to {@code dest}, {@code false} otherwise
*/
public boolean hasPathBFS(E src, E dest) {
GraphNode<E> s = nodes.get(src);
GraphNode<E> d = nodes.get(dest);
if (s == null || d == null) {
return false;
}
Set<GraphNode<E>> visited = new HashSet<>();
Queue<GraphNode<E>> toVisit = new ArrayDeque<>();
toVisit.add(s);
return hasPathBFS(d, visited, toVisit);
}
private boolean hasPathBFS(GraphNode<E> dest, Set<GraphNode<E>> visited, Queue<GraphNode<E>> toVisit) {
while (!toVisit.isEmpty()) {
GraphNode<E> node = toVisit.poll();
if (visited.contains(node)) {
continue;
} else {
visited.add(node);
}
toVisit.addAll(node.adjacentNodes.stream().filter(n -> !visited.contains(n)).collect(Collectors.toList()));
if (node.value.compareTo(dest.value) == 0) {
return true;
}
}
return false;
}
/**
* Prints the node values in the graph.
*/
public void print() {
Set<E> visited = new HashSet<>();
System.out.print("[");
Iterator<E> iterator = nodes.keySet().iterator();
while (iterator.hasNext()) {
E node = iterator.next();
if (!visited.contains(node)) {
visited.add(node);
System.out.print(node);
if (iterator.hasNext()) {
System.out.print(", ");
}
}
}
System.out.println("]");
}
public static void main(String[] args) {
UndirectedGraph<Integer> graph = new UndirectedGraph<>();
graph.addEdge(1, 4);
graph.addEdge(4, 5);
graph.addEdge(4, 6);
graph.addEdge(4, 7);
graph.addEdge(5, 1);
graph.addEdge(5, 6);
graph.addEdge(8, null);
graph.addEdge(null, 9);
graph.print();
System.out.println("----");
// has path DFS
System.out.println(graph.hasPathDFS(1, 5));
System.out.println(graph.hasPathDFS(1, 6));
System.out.println(graph.hasPathDFS(1, 8));
System.out.println(graph.hasPathDFS(4, 8));
System.out.println(graph.hasPathDFS(4, 9));
System.out.println(graph.hasPathDFS(4, 100));
System.out.println("----");
// has path BFS
System.out.println(graph.hasPathBFS(1, 5));
System.out.println(graph.hasPathBFS(1, 6));
System.out.println(graph.hasPathBFS(1, 8));
System.out.println(graph.hasPathBFS(4, 8));
System.out.println(graph.hasPathBFS(4, 9));
System.out.println(graph.hasPathBFS(4, 100));
}
}