I have an array of strings that represents the edges of a graph.
For example:
["6 11", "9 5", "11 9", "15 9", "13 15", "12 14", "15 16", "1 16"]
Now I want to create a graph for this so I can see how many nodes are connected and how many are not connected. I am not sure what approach to follow for this.
I have used a Map in my program but I am not able to group the nodes properly in my code:
public static void process(int n, List<String> input) {
Map<Integer, Set<Integer>> map = new HashMap<>();
for (String in : input) {
String[] arr = in.split(" ");
int a1 = Integer.parseInt(arr[0]);
int a2 = Integer.parseInt(arr[1]);
int first = Math.min(a1, a2);
int second = Math.max(a1, a2);
if (map.size() == 0) {
Set<Integer> s = new HashSet<>();
s.add(first);
s.add(second);
map.put(first, s);
continue;
}
boolean found = false;
for (int k : map.keySet()) {
Set<Integer> set = map.get(k);
if (set.contains(first)) {
map.get(k).add(second);
found = true;
break;
}
if (set.contains(second)) {
map.get(k).add(first);
found = true;
break;
}
}
if (!found) {
Set<Integer> s = new HashSet<>();
s.add(first);
s.add(second);
map.put(first, s);
}
}
System.out.println(map);
}
Now with this program I am getting a map with below values:
{5=[16, 1, 5, 9, 11, 13, 15], 6=[6, 11], 12=[12, 14]}
The problem here is, I already have 11 for map key = 5. So node 6 should be added to the set for key = 5 itself. So the map should look like this:
{5=[16, 1, 5, 9, 11, 13, 15, 6], 12=[12, 14]}
How to do this, what approach I need to follow here? Here I used a map just for convenience because in a later step I wanted to count the size of each key means: 5 has 8 nodes, 12 has 2 nodes, etc. Nodes which are not having edges are 2, 3, 4, 7, 8, 10.
Here keys 5 and 12 are not important for me, they can be anything. Also, the order of values is also not important for me they can be in any order.
Edit:
In the input: ["6 11", "9 5", "11 9", "15 9", "13 15", "12 14", "15 16", "1 16"]
say "6 11", both 6 and 11 are nodes and the "6 11" represents an edge between nodes. Now I just want to group all connected nodes like "6 11 9 15 13 16 1 5" and another group "12 14".
Update:
I tried implementing the Javascript solution given by grodzi in Java but it is giving the wrong output, I made a mistake while conversion which I am not able to understand:
public static int process(int n, List<String> input) {
Map<String, Integer> strToGroupId = new HashMap<>();
Map<Integer, Set<Integer>> groupIdToGroup = new HashMap<>();
for (String in : input) {
String[] arr = in.split(" ");
int a1 = Integer.parseInt(arr[0]);
int a2 = Integer.parseInt(arr[1]);
link(arr[1], arr[1], strToGroupId, groupIdToGroup);
}
System.out.println(groupIdToGroup);//{16=[16], 5=[5], 9=[9], 11=[11], 14=[14], 15=[15]
return 0;
}
static void link(String strA, String strB, Map<String, Integer> strToGroupId, Map<Integer, Set<Integer>> groupIdToGroup) {
if (!strToGroupId.containsKey(strA)) {
int val = Integer.parseInt(strA);
strToGroupId.put(strA, val);
Set<Integer> set = new HashSet<>();
set.add(val);
groupIdToGroup.put(val, set);
}
if (!strToGroupId.containsKey(strB)) {
int val = Integer.parseInt(strB);
strToGroupId.put(strB, val);
Set<Integer> set = new HashSet<>();
set.add(val);
groupIdToGroup.put(val, set);
}
int gA = strToGroupId.get(strA);
int gB = strToGroupId.get(strB);
if (gA == gB) return;
// need to merge
Set<Integer> eaters = groupIdToGroup.get(gA);
Set<Integer> eatens = groupIdToGroup.get(gB);
for (int n : eatens) {
eaters.add(n);
strToGroupId.put(n+"", gA); // the eateN now links to gA instead of gB
}
groupIdToGroup.remove(gB); // gB does not exist anymore
}
Update using DFS approach
Now I am trying to follow the approach suggested by Abhinav Mathur. Here is my Java code, it is generating wrong results:
public static void process(int n, List<String> input) {
List<Set<Integer>> graph = new ArrayList<>();
List<Set<Integer>> output = new ArrayList<>();
for (int i = 0; i < n; i++) {
graph.add(new HashSet<>());
}
for (int i = 0; i < n; i++) {
output.add(new HashSet<>());
}
for (String in : input) {
String[] arr = in.split(" ");
int a1 = Integer.parseInt(arr[0]);
int a2 = Integer.parseInt(arr[1]);
graph.get(a1-1).add(a2);
graph.get(a2-1).add(a1);
}
boolean[] visited = new boolean[n];
for (int i = 0; i < n; i++) {
dfs(1, 1, visited, graph, output);
}
System.out.println(output);
}
private static void dfs(int node, int source, boolean[] visited, List<Set<Integer>> graph,
List<Set<Integer>> output) {
if (!visited[node-1]) {
visited[node-1] = true;
output.get(source-1).add(node);
for (int neighbour : graph.get(node-1)) {
dfs(neighbour, source, visited, graph, output);
}
}
}
For input "6 11", "9 5", "11 9", "15 9", "13 15", "12 14", "15 16", "1 16", this program returns:
[[16, 1, 5, 6, 9, 11, 13, 15], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]