I am working on a undirected friendship graph which consists of students who are friends at a particular school. I want to get cliques(all connected subgraphs from the graph) using dfs. But for some reason my dfs is not working correctly.. Any suggestions on the algorithm or the code is appreciated
this is a sample graph created manually..
import java.util.LinkedHashMap;
public class DFS {
/**
* #param args
*/
class Node {
String personName, schoolName;
Node next;
public Node(String personName, String schoolName, Node next) {
this.personName = personName;
this.schoolName = schoolName;
this.next = next;
}
public String toString() {
return this.personName + " " + this.schoolName;
}
}
public Node[] build() {
Node[] graph = new Node[6];
for (int i = 0; i < graph.length; i++) {
Node temp = new Node(Integer.toString(i + 1), "MIT", null);
graph[i] = temp;
}
graph[0].next = new Node("2", "MIT", null);
graph[1].next = new Node("1", "MIT", null);
graph[1].next.next = new Node("3", "MIT", null);
graph[1].next.next.next = new Node("4", "MIT", null);
graph[2].next = new Node("2", "MIT", null);
graph[2].next.next = new Node("4", "MIT", null);
graph[3].next = new Node("3", "MIT", null);
graph[3].next.next = new Node("2", "MIT", null);
graph[4].next = new Node("6", "MIT", null);
graph[5].next = new Node("5", "MIT", null);
printGraph(graph);
return graph;
}
public void dfsDriver() {
Node[] graph = build();
LinkedHashMap<String, Integer> names = new LinkedHashMap<String, Integer>();
int count = 0;
for (int i = 0; i < graph.length; i++) {
if (graph[i] != null) {
names.put(graph[i].personName, count);
count++;
}
}
boolean[] visited = new boolean[graph.length];
for (int v = 0; v < visited.length; v++) {
visited[v] = false;
}
for (int i = 0; i < graph.length; i++) {
if (graph[i] != null) {
if (!visited[i]) {
System.out.println("Starting at " + graph[i].personName);
dfs(i, visited, names, graph);
}
}
}
}
private void dfs(int i, boolean[] visited, LinkedHashMap<String, Integer> names, Node[] subGraph) {
visited[i] = true;
for (Node e = subGraph[i].next; e != null; e = e.next) {
System.out.println("visiting " + e.personName);
int index = names.get(e.personName);
if (!visited[index]) {
dfs(index, visited, names, subGraph);
}
}
}
public void printGraph(Node[] list) {
System.out.println();
for (int i = 0; i < list.length; i++) {
if (list[i] != null) {
System.out.print(list[i]);
for (Node a = list[i].next; a != null; a = a.next) {
System.out.print(" " + a);
}
System.out.println();
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
DFS a = new DFS();
a.dfsDriver();
}
}
#1 : The graph creation is inefficient.
See this method in your code:
public Node[] build() {
There are 6 nodes that you wanted and look how many times are you calling "new Node". Its 6 + 10 times..Try to modify your data structures so that they suit to the inputs.
The current DS is :
class Node {
String personName, schoolName;
Node next;
Think about modifying this so that each node can "point" to multiple other nodes without creating new object for its frends every time.
#2 Confusing print statement in dfs method()
It should be like this:
private void dfs(int i, boolean[] visited,
LinkedHashMap<String, Integer> names, Node[] subGraph) {
visited[i] = true;
for (Node e = subGraph[i].next; e != null; e = e.next) {
int index = names.get(e.personName);
if (!visited[index]) {
System.out.println("visiting " + e.personName);
dfs(index, visited, names, subGraph);
}
}
}
#3: There is no mechanism to store the end results
You want all connected subgraphs from the main graph. However I dont see any provision to store/ mark the graph. You can modify the 2nd for loop inside public void dfsDriver() method so that it will create a new graph from the NEW nodes visited after each iteration.
Related
I was asked this question in one of my google interviews. I couldn't figure it out. If someone can help that would be great :)
The class provided was
class Node{
int data,
List<Node> outEdges;
}
if you're provided a Node stream containing both directed and undirected edges you have to encode it in such a way that it return List and and decode again to original graph
List<Integer> encode(Node root){
}
Node decode(List<Integer> graph){
}
The hint provided was you can add your own integers if you want
You could just put the data and all the edges in the list and using null as delimiter:
private class IndexAndEdge {
public Set<Integer> edges = new HashSet<>();
public int index;
public int data;
}
List<Integer> encode(Node root) {
List<Integer> result = new ArrayList<>();
Map<Node, IndexAndEdge> lookup = new HashMap<>();
parse(root, lookup);
result.add(lookup.size());
lookup.values().stream()
.sorted((a, b) -> Integer.compare(a.index, b.index))
.forEach(iae -> {
result.add(iae.data);
result.addAll(iae.edges);
result.add(null);
});
result.remove(result.size() - 1);
return result;
}
private int parse(Node node, Map<Node, IndexAndEdge> lookup) {
if (lookup.containsKey(node))
return lookup.get(node).index;
IndexAndEdge iae = new IndexAndEdge();
iae.index = lookup.size();
iae.data = node.data;
lookup.put(node, iae);
for (Node n : node.outEdges)
iae.edges.add(parse(n, lookup));
return iae.index;
}
Node decode(List<Integer> graph) {
Node[] nodes = new Node[graph.get(0)];
for (int i = 0; i < nodes.length; i++) {
nodes[i] = new Node();
nodes[i].outEdges = new ArrayList<>();
}
int index = 0;
for (int i = 1; i < graph.size(); i++) {
Integer n = graph.get(i);
if (n == null)
index++;
else if (nodes[index].outEdges.isEmpty())
nodes[index].data = n;
else
nodes[index].outEdges.add(nodes[n]);
}
return nodes[0];
}
What is the problem here?.I'm trying to implement the graph data structure,using the adjacency lists,by utilising the Collections from the util package.Here
LinkedList array which holds some integer.
Each element of that LinkedList holds another LinkedList of type: node.
But during the compilation process, it says incompatible types.
How to resolve this problem?
//Sum of dependencies in a graph
import java.util.*;
class node
{
int vertex,weight;
public node(int v,int w)
{
vertex = v;
weight = w;
}
}
public class dependency
{
int V;
LinkedList<Integer> adj[];
public dependency(int v)
{
V = v;
adj = new LinkedList<Integer>[v];
for (int i=0;i < v ;i++ ) {
adj[i] = new LinkedList<node>();
}
}
void addEdge(int v,node l)
{
adj[v].add(l);
}
void BFS(int s)
{
boolean visited[] = new boolean[V];
LinkedList<Integer> queue = new LinkedList<Integer>();
visited[s] = true;
queue.add(s);
while(queue.size() != 0)
{
s = queue.poll();
System.out.println(s+" ");
Iterator<Integer> i = adj[s].listIterator();
while(i.hasNext())
{
int n = i.next();
if(!visited[n])
{
visited[n] = true;
queue.add(n);
}
}
}
}
public static void main(String[] args) {
graph g = new graph(4);
node a = new node(1,10);
node b = new node(2,20);
node c = new node(2,30);
node d = new node(0,20);
node e = new node(3,30);
node f = new node(3,20);
g.addEdge(0, a);
g.addEdge(0, b);
g.addEdge(1, c);
g.addEdge(2, d);
g.addEdge(2, e);
g.addEdge(3, f);
System.out.println("Following is Breadth First Traversal "+
"(starting from vertex 2)");
g.BFS(2);
}
}
You've declared an array of LinkedLists of type LinkedList<Integer>, but you're trying to store LinkedList<node> in the array. It doesn't appear that you're ever using the weight attribute of node, so you should change adj[i] = new LinkedList<node>(); to adj[i] = new LinkedList<Integer>();.
I am working to get the shortest reach in a graph problem in hackercode. I have designed a code and some testcases are fine whereas some testcases are terminated due to timeout.
Could you say where I need to optimize and please also comment about code style. I am looking for the ways to improve it.
Following is my code,
public class BFS {
public static class Graph {
public Node[] nodes;
Stack<Node> stack = new Stack<Node>();
public Graph(int size) {
nodes = new Node[size];
}
public void addEdge(int first, int second) {
Node nodeF = getNode(first);
if (nodeF == null) {
nodeF = new Node();
nodeF.nodeVal = first;
}
Node nodeS = getNode(second);
if (nodeS == null) {
nodeS = new Node();
nodeS.nodeVal = second;
}
nodeF.neighbours.add(nodeS);
nodes[first] = nodeF;
nodes[second] = nodeS;
}
public int[] shortestReach(int startId) { // 0 indexed
stack.push(getNode(startId));
int[] distance = new int[nodes.length];
Arrays.fill(distance, -1);
distance[startId] = 0;
while (!stack.isEmpty()) {
Node currentNode = stack.pop();
Set<Node> children = getChildren(currentNode);
for (Node node : children) {
distance[node.nodeVal] = distance[currentNode.nodeVal] + 6;
stack.add(node);
}
}
return distance;
}
public Set<Node> getChildren(Node givenNode) {
for (Node node : nodes) {
if (node == givenNode) {
return node.neighbours;
}
}
return null;
}
public Node getNode(int index) {
return nodes[index];
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int queries = scanner.nextInt();
for (int t = 0; t < queries; t++) {
// Create a graph of size n where each edge weight is 6:
Graph graph = new Graph(scanner.nextInt());
int m = scanner.nextInt();
// read and set edges
for (int i = 0; i < m; i++) {
int u = scanner.nextInt() - 1;
int v = scanner.nextInt() - 1;
// add each edge to the graph
graph.addEdge(u, v);
}
// Find shortest reach from node s
int startId = scanner.nextInt() - 1;
int[] distances = graph.shortestReach(startId);
for (int i = 0; i < distances.length; i++) {
if (i != startId) {
if (distances[i] == 0)
continue;
System.out.print(distances[i]);
System.out.print(" ");
}
}
System.out.println();
}
scanner.close();
}
}
class Node {
public int nodeVal;
public Set<Node> neighbours = new HashSet<Node>();
}
Here's my code for insertion of a node in a compressed suffix trie :
public class tree {
char a[] = new char[10];
a[0]='b';
a[1]='a';
a[2]='n';
a[3]='a';
a[4]='n';
a[5]='a';
a[6]=' ';
protected node root;
public tree() {
this.root = new node();
}
public void inorder(node n) {
if (n.getChildren().next != null) {
inorder(n.getChildren().next.getChild());
}
System.out.println(n.getStart() + n.getEnd());
if (n.getChildren().next.next != null) {
inorder(n.getChildren().next.next.getChild());
}
}
public void insert(node n, node r) {
while (n.getStart() != 6) {
if (r.getChildren().next == null) {
//when the tree is empty :
n.setParent(r);
n.getChildren().setNext(null);
link newn = new link();
newn.setNext(null);
newn.setChild(n);
r.getChildren().next = newn;
node newnode = n;
newnode.setStart(n.getStart() + 1);
insert(newnode, r);
}
else {
// count is the node where we begin checking for same letters :
node count = r.getChildren().next.getChild();
// l is the linked list containing children of the node :
link l = r.getChildren().next;
while ((a[count.getStart()] != a[n.getStart()])
|| (l.next != null)) {
l = l.next;
count = l.getChild();
}
// create a new link node corresponding to the node to be inserted
// only for the case when we reach the end of the list :
link h = new link();
h.setNext(null);
h.setChild(n);
// we have reached the end of the linked list :
if ((a[count.getStart()] != a[n.getStart()])
&& (l.next == null)) {
if (n.getStart() != n.getEnd()) {
l.setNext(h);
h.setNext(null);
h.setChild(n);
n.setParent(r);
n.getChildren().setNext(null);
node newnode = n;
newnode.setStart(n.getStart() + 1);
insert(newnode, r);
}
else {
l.setNext(h);
h.setNext(null);
h.setChild(n);
n.setParent(r);
n.getChildren().setNext(null);
node newnode = new node();
newnode.setStart(count.getStart() + 1);
newnode.setEnd(n.getEnd());
}
}
// if we have found an element whose characters
// match that of the node:
else {
link kids = count.getChildren();
int x = count.getStart();
int y = n.getStart();
int p = count.getEnd();
int q = n.getEnd();
int t1 = count.getStart();
int t2 = n.getStart();
int length = p - x + 1;
int same = 1;
while (a[x + 1] == a[y + 1]) {
x++;
y++;
same++;
}
int g = length - same;
//modifying the node r:
count.setStart(t1);
count.setEnd(x);
// creating the 2 new nodes to be inserted below count if
// count initially doesnt have any children :
node kid1 = new node();
kid1.setStart(x + 1);
kid1.setEnd(p);
kid1.getChildren().setNext(null);
node kid2 = new node();
kid2.setStart(y + 1);
kid2.setEnd(q);
// creating 2 new link nodes to be inserted in
// the children list of count :
link k1 = new link();
link k2 = new link();
k1.setChild(kid1);
k2.setChild(kid2);
k1.setNext(k2);
k2.setNext(null);
//changing relationships :
kid1.setChildren(kids);
kid1.setParent(count);
count.getChildren().next.setNext(k1);
while (kids.next != null) {
kids.next.getChild().setParent(kid1);
kids = kids.next;
}
insert(kid2, count);
}
}
}
}
public static void main(String[] args) {
tree t = new tree();
node banana = new node();
banana.setStart(0);
banana.setEnd(7);
banana.getChildren().setNext(null);
t.insert(banana, t.root);
//inorder(tree.root);
}
}
When I run it in Eclipse, it says that it has some unresolved compilation problem.
Can you please help me sort this out? Thanks.
You cannot have non-declarative statements in the class block.
a[0]='b';
a[1]='a';
...
All these array assignments belong in a method, constructor or static initializer block. Alternatively, if adjusting the length or your array, is an option you could simply use:
char a[] = "banana".toCharArray();
Anyone know where I can obtain generic sample code for using an adjacency list to represent an undirected graph?
The graph data would be from a .txt file: The nodes are specified on the first line, separated by spaces. The edges are specified on the following lines, each edge on a separate line.
Like this...
1 2 3 4 5 6 7 8 9
1 2
1 4
1 3
2 4
2 5
3 6
4 6
5 7
5 8
6 9
7 9
8 9
My .txt file isn't connecting with the graph methods. I'm also getting the following NPE error:
Error: java.lang.NullPointerException
Creating an adjacency list & performing standard Graph ADT methods for the undirected graph.
//TON of imports up here (removed for now)
class Graph<V> implements GraphADT1 <V>{
// Map of adjacency lists for each node
private HashMap<Integer, LinkedList<Integer>> adj;
private ArrayList<V> vertices;
private HashMap<V, LinkedHashSet<V>> neighbors;
private HashMap<V, Set<V>> neighborsView;
private int edgeCount;
public Graph(int[] nodes) {
vertices = new ArrayList<V>();
neighbors = new HashMap<V, LinkedHashSet<V>>();
neighborsView = new HashMap<V, Set<V>>();
adj = new HashMap<Integer, LinkedList<Integer>>();
for (int i = 0; i < nodes.length; ++i) {
adj.put(i, new LinkedList<Integer>());
}
}
//Add Vertex Method
public void addVertex(V vid) {
vertices.add(vid);
LinkedHashSet<V> neighborV = new LinkedHashSet<V>();
neighbors.put(vid, neighborV);
neighborsView.put(vid, Collections.unmodifiableSet(neighborV));
}
// Removes Vertex Method
public void removeVertex(V vid) {
if(vertices.remove(vid)) {
LinkedHashSet<V> neighborV = neighbors.remove(vid);
for(V uid : neighborV) {
LinkedHashSet<V> neighborU = neighbors.get(uid);
neighborU.remove(vid);
--edgeCount;
}
neighborsView.remove(vid);
} else {
throw new NoSuchElementException("no such vertex");
}
}
//Add Edge Method
public void addEdge(V uid, V vid) {
LinkedHashSet<V> neighborU = neighbors.get(uid);
LinkedHashSet<V> neighborV = neighbors.get(vid);
if(neighborU == null) throw new NoSuchElementException("first argument not in graph");
if(neighborV == null) throw new NoSuchElementException("second argument not in graph");
if(neighborU.add(vid) && neighborV.add(uid)) {
++edgeCount;
}
}
//Remove Edge Method
public void removeEdge(V uid, V vid) {
LinkedHashSet<V> neighborU = neighbors.get(uid);
LinkedHashSet<V> neighborV = neighbors.get(vid);
if(neighborU == null) throw new NoSuchElementException("first argument not in graph");
if(neighborV == null) throw new NoSuchElementException("second argument not in graph");
if(neighborU.remove(vid) && neighborV.remove(uid)) {
--edgeCount;
} else {
throw new NoSuchElementException("no edge between vertices");
}
}
public void addNeighbor(int neighborV, int neighborU) {
adj.get(neighborV).add(neighborU);
}
public List<Integer> getNeighbors(int v) {
return adj.get(v);
}
public static void main(String[] args) {
try {
File file = new File("data.txt");
InputStreamReader streamReader = new InputStreamReader(
new FileInputStream(file));
BufferedReader br = new BufferedReader(streamReader);
String line = br.readLine();
if (line != null) {
// read nodes
String[] nodeNames = line.split(" ");
int[] nodes = new int[nodeNames.length];
for (int i = 0; i < nodes.length; ++i) {
nodes[i] = Integer.parseInt(nodeNames[i]);
}
// create graph
Graph V = new Graph(nodes);
// read edges
while ((line = br.readLine()) != null) {
String[] tokens = line.split(" ");
int neighborV = Integer.parseInt(tokens[0]);
int neighborU = Integer.parseInt(tokens[1]);
// we add neighbor to each node in both directions.
V.addNeighbor(neighborV, neighborU);
V.addNeighbor(neighborU, neighborV);
}
}
br.close();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} catch (Exception e) {
System.out.println("Error: " + e);
}
}
public Iterator<?> iteratorBFS(Object startVertex) {
return null;
}
public Iterator<?> iteratorDFS(Object startVertex) {
return null;
}
public boolean isEmpty() {
return size() == 0;
}
public boolean isConnected() {
return false;
}
public int size() {
return 0;
}
}
You can enclose your graph in class:
class Graph {
//Map of adjacency lists for each node
Map<Integer, List<Integer>> adj;
public Graph(int[] nodes) {
//your node labels are consecutive integers starting with one.
//to make the indexing easier we will allocate an array of adjacency one element larger than necessary
adj = new HashMap<Integer, LinkedList<Integer>>();
for (int i = 0; i < nodes.length; ++i) {
adj.put(i, new LinkedList<Integer>());
}
}
public addNeighbor(int v1, int v2) {
adj.get(v1).add(v2);
}
public List<Integer> getNeighbors(int v) {
return adj.get(v);
}
}
And then read it more or less like this:
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new StreamReader(System.in));
String line = br.readLine();
if (line != null) {
//read nodes
String[] nodeNames = line.split(" ");
int[] nodes = new int[nodeNames.length]
for (int i = 0; i < nodes.length; ++i) {
nodes[i] = Integer.parseInt(nodeNames[i]);
}
//create graph
Graph g = new Graph(nodes);
//read edges
while((line = br.readLine()) != null) {
String[] tokens = line.split(" ");
int v1 = Integer.parseInt(tokens[0]);
int v2 = Integer.parseInt(tokens[1]);
//we add neighbor to each node in both directions.
g.addNeighbor(v1, v2);
g.addNeighbor(v2, v1);
}
}
br.close();
}
catch(exceptions) {
handle them
}
}
public static void main(String [] Args){
try {
Scanner s = new Scanner(new File("your file.txt"));
StringTokenizer t = new StringTokenizer(s.nextLine());
Hashtable<Integer,Node> nodes = new Hashtable<Integer,Node>();
while(t.hasMoreTokens()){
int id = Integer.parseInt(t.nextToken());
nodes.put(id, new Node(id));
}
while(s.hasNextInt()){
Node e1 = nodes.get(s.nextInt());
Node e2 = nodes.get(s.nextInt());
e1.adjacent.add(e2);
e2.adjacent.add(e1);
}
\\now you can use the nodes Map above to retrieve nodes or to get a list:
List<Node> adjencyNodeList = new ArrayList(nodes.values());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class Node {
int id;
List<Node> adjacent = new ArrayList<Node>();
public Node(int id){
this.id = id;
}
}