Build graph given coordinates of adjacent nodes - java

The way you can interpret this is as such:
nodeName
nodeName's x-coord, nodeName's y-coord
x-coord of an adjacent node, y-coord of that adjacent node
...and the rest are just more coordinates of adjacent nodes. I'm trying to figure out how to store this as a graph so I can check if a path is legal. For example, maybe nodeA-nodeB-nodeC is legal, but nodeA-nodeC-nodeD is not.
So, my final question is: what is the best way to code the Graph class, and populate it by reading in this data?

You can split file to groups of lines. Each group describes node. And then parse all groups.
Map<Node, List<Node>> neighbors;
Map<String, Node> nodeByCoords;
// Get node by it's coordinates. Create new node, if it doesn't exist.
Node getNode(String coords) {
String[] crds = coords.split(" ");
int x = Integer.parseInt(crds[0]);
int y = Integer.parseInt(crds[1]);
String key = x + " " + y;
if (!nodeByCoords.containsKey(key)) {
Node node = new Node();
node.setX(x);
node.setY(y);
nodeByCoords.put(key, node);
neighbords.put(node, new ArrayList<Node>());
}
return nodeByCoords.get(key);
}
// Create node (if not exists) and add neighbors.
void List<String> readNode(List<String> description) {
Node node = getNode(description.get(1));
node.setName(description.get(0));
for (int i = 2; i < description.size(); i++) {
Node neighbor = getNode(description.get(i));
neighbors.get(node).add(neighbor);
}
}
// Splits lines to groups. Each group describes particular node.
List<List<String>> splitLinesByGroups (String filename) {
BufferedReader reader = new BufferedReader(new FileReader(filename));
List<List<String>> groups = new ArrayList<List<String>>();
List<String> group = new ArrayList<String>();
while (reader.ready()) {
String line = reader.readLine();
if (Character.isLetter(line.charAt())) {
groups.add(group);
group = new ArrayList<String>();
}
group.add(line);
}
groups.add(group);
return groups;
}
// Read file, split it to groups and read nodes from groups.
void readGraph(String filename) {
List<List<String>> groups = splitLineByGroups(filename);
for (List<String> group: groups) {
readNode(group);
}
}

I think there is no need to store nodes somehow to find out whether the path is legal: you can check the legalty of the next node when reading them. The next node is legal if and only if it's coordinates differ to previous ones by no more than 1.

You might want to consider using JGraphT
You could just create an instance of the SimpleGraph and populate it with nodes and edges:
// Define your node, override 'equals' and 'hashCode'
public class Node {
public int x, y;
Node (int _x, int _y) {
x = _x;
y = _y;
}
#Override public boolean equals (Object other) {
if ( (other.x == x)
&& (other.y == y))
return true;
return false;
}
/* Override hashCode also */
}
// Later on, you just add edges and vertices to your graph
SimpleGraph<Node,Edge> sg;
sg.addEdge (...);
sg.addVertex (...);
Finally, you can use DijkstraShortestPath to find whether or not a path exists:

Related

Directed graph in java using a hashmap

I have implemented a directed graph in java, using Map data structure.
Currently, I have two Map data structures:
Holds each Node, with All in-degree vertices.
Holds each Node, with All out-degree vertices.
My problem is as follows:
I would like to implement a shortest path algorithm that, given a specific node and a secondary node, finds the shortest path between the first node to the second node.
I am not sure how to implement it using Map data structure.
public class NetworkInfluence {
private int numEdges; //number of edges
private int numVert; //number of vertices
private int numIter; //number of page rank iterations
private Map<String, List<String>> AtoB; //out degree of vertices
private Map<String, List<String>> BtoA; //in degree of vertices
private Map<String, Double> influenceMap; //page ranks of vertices
private Set<String> nodeCounter; //list of vertices
/**
* Creates a new PageRank object. This is used to find the pagerank
* of a graph represented as an edgelist in a text file.
* #param fileName Name of text file containing graph edge list.
* #param eps Convergence parameter for pagerank.
* #throws FileNotFoundException If text file containing graph cannot be found.
* #throws IOException If error reading a text file.
*/
public NetworkInfluence(String fileName) throws FileNotFoundException, IOException {
numIter = 0;
numEdges = 0;
AtoB = new HashMap<String, List<String>>();
BtoA = new HashMap<String, List<String>>();
Set<String> nodeCounter = new HashSet<String>();
FileReader fr = new FileReader(fileName);
BufferedReader b = new BufferedReader(fr);
String line = b.readLine();
String nodes[];
List<String> toList;
List<String> fromList;
while((line = b.readLine()) != null) {
numEdges++;
nodes = line.toLowerCase().split(" ");
//A->B
if(!AtoB.containsKey(nodes[0])) {
toList = new ArrayList<String>();
toList.add(nodes[1]);
AtoB.put(nodes[0], toList);
} else {
toList = AtoB.get(nodes[0]);
toList.add(nodes[1]);
AtoB.put(nodes[0], toList);
}
//B->A
if(!BtoA.containsKey(nodes[1])) {
fromList = new ArrayList<String>();
fromList.add(nodes[0]);
BtoA.put(nodes[1], fromList);
} else {
fromList = BtoA.get(nodes[1]);
fromList.add(nodes[0]);
BtoA.put(nodes[1], fromList);
}
nodeCounter.add(nodes[0]);
nodeCounter.add(nodes[1]);
}
this.nodeCounter = nodeCounter;
numVert = nodeCounter.size();
b.close();
Any help would be appreciated. Thanks.
As mentioned you can solve it with dijkstra even if you are using hashmaps. In addition to your structure you have to somehow the costs of edges, something like this:
Map<String, Map<String, Integer>> costs = new HashMap<>();
...
// where the cost of edge ("node0", "node1") is:
int cost = costs.get("node0").get("node1");
the part od dijkstra may be something like this (i did not care about optimizing map access):
public List<String> path(String node0, String node1) {
// array to keep trace of visited nodes
Map<String, Boolean> visited = new HashMap<>();
// array to keep trace of predecessors of nodes in the path
Map<String, String> pred = new HashMap<>();
// initialize maps
for (String n : nodeCounter) {
visited.put(n, false);
pred.put(n, node0);
}
// min costs from node0 to any other node, initialized to INFINITE if
// the nodes are not adjacent
Map<String, Integer> mincosts = new HashMap<>();
for (String n : nodeCounter)
mincosts.put(n, costs.get(node0).get(n));
// initialize flags of start node
visited.put(node0, true);
mincosts.put(node0, 0);
// iterate until all vertexes or node1 are reached
for (int i = 0; (i < numVert) && (!visited.get(node1)); ++i) {
int min = inf;
String candidate = null;
for (String n : nodeCounter)
if (!visited.get(n) && mincosts.get(n) < min) {
min = mincosts.get(n);
candidate = n;
}
if (candidate == null)
break;
visited.put(candidate, true);
for (String n : nodeCounter)
if (!visited.get(n) && ((mincosts.get(candidate) + costs.get(candidate).get(n)) < mincosts.get(n))) {
mincosts.put(n, mincosts.get(candidate) + costs.get(candidate).get(n));
pred.put(n, candidate);
}
}
if (!visited.get(node1))
return null;
// store the path from node1 to node0, using predecessors
// map
String current = node1;
List<String> path = new ArrayList<>();
path.add(current);
while (!current.equals(node0))
path.add(current = pred.get(current));
// store the path from node0 to node1
Collections.reverse(path);
return path;
}
Actually, if you can use also third libraries, i suggest you to look for a graph java library like JGraphT, and use the given functions for minimum paths. For example here is the reference for the Dijkstra JGraphT API.

Correct Iterator method for switching consecutive list elements

Writing a method meant to store a list element to a variable in order to switch it with the next element in the array.
There are currently two variables for storage (which may or may not mean there's an extra).
The goal is to use the correct iterator (unless there's a better method) to switch the stored element with the next in the fewest lines possible.
public void sort(List<Point> lst) {
for (int st = 0; st < lst.size(); st++) { //defines first element-to-compare.
for (int wt = 1; wt< lst.size(); wt++) { //defines second element-to-compare.
double one = lst.get(st).distanceToOrigin(); //stores variable describing distance-to-origin for point one;
//if lst.get(st)>lst.get(wt), am switching element places in list.
//if lst.get(st) > lst.get(wt), switch the pair of consecutive elements.
double two = lst.get(wt).distanceToOrigin(); //stores variable describing distance-to-origin for point two;
//represents element to switch if lst.get(wt) < lst.get(st)
Point tmp1;
Point tmp2;
if (one > two){
tmp1 = lst.get(st);
lst.remove(lst.get(st));
tmp2 = lst.nextPoint();
}
}
}
}
Right now I'm using the hasNext() method in order to check if there is another element after lst.get(st):
if (one > two) {
tmp1 = lst.get(st);
lst.remove(lst.get(st));
while (lst.distanceToOrigin.hasNext()) { //this line does not work in editor.
//Attempting to refine.
//TODO switch elements described by double one and double two.
}
}
Insight is greatly appreciated.
You can use the methods of List for changing the elements order:
if(one > two) {
Point tmp1 = list.get(st);
Point tmp2 = list.get(wt);
lst.set(st, tmp2);
lst.set(wt, tmp1);
}
//....
Another approach: If each Point-Object "knows" the origin, it could also be an option to use the Comparable-Interface:
public class Point implements Comparable {
Point origin;
//other variables...
//constructor and methods...
#Override
public int compareTo(Point other) {
Double.compare(this.distanceToOrigin(), other.distanceToOrigin());
}
}
And your sort()-method:
public void sort(List<Point> lst) {
Collections.sort(lst);
}

From BST (binary search tree) to linkedlist array

A binary search tree was created by traversing through an array from left to right and inserting each element. This tree may not be a balanced tree. Given a binary search tree with distinct elements, print all possible arrays that could have led to this tree.
To answer to this question I wrote the following code. Still, it seems that it doesn't print all possible arrays that could have lead to the the tree in all the cases. What do you think should be modified ?
public class Main {
public static LinkedList<Integer> passed = new LinkedList<>();
public static LinkedList<BinaryTree> notyet = new LinkedList<>();
public static ArrayList<LinkedList<Integer>> results = new ArrayList<LinkedList<Integer>>();
public static void main(String args[]) {
BinaryTree tr = readTree();
ArrayList<LinkedList<Integer>> result = allSequences(tr);
for (LinkedList<Integer> l : result){
for(int elem: l) System.out.print(elem+" ");
System.out.println("");
}
}
private static BinaryTree readTree() {
BinaryTree tr = new BinaryTree(2, null, null);
tr.left = new BinaryTree(1, null, null);
tr.right = new BinaryTree(3, null, null);
return tr;
}
public static ArrayList<LinkedList<Integer>> allSequences(BinaryTree tr){
// implement here
ArrayList<LinkedList<Integer>> result = new ArrayList<LinkedList<Integer>>();
findseqs(passed,notyet,tr);
//result=results.clone();
for(LinkedList<Integer> sample :results){
result.add(sample);
}
return result;
}
public static void findseqs(LinkedList<Integer> passed, LinkedList<BinaryTree> notyet, BinaryTree tr) {
passed.add(tr.value);
if (tr.left != null) notyet.add(tr.left);
if (tr.right != null) notyet.add(tr.right);
if (notyet.isEmpty()) {
results.add(passed);
}
for (BinaryTree elem: notyet) {
LinkedList<Integer> temp = (LinkedList<Integer>) passed.clone();
LinkedList<BinaryTree> ptemp = (LinkedList<BinaryTree>) notyet.clone();
ptemp.remove(elem);
findseqs(temp, ptemp, elem);
}
}
What holds about the array is that if A is ancestor of B in the graph then A precedes B in the array. Nothing else can be assumed.
So the arrays can be produced by the following recursive function.
function sourceArrays(Tree t)
// leafe node
if t == null
return empty list;
r = root(t);
append r to existing arrays;
la = sourceArrays(t.left);
ra = sourceArrays(t.right);
ac = createArrayCombitations(la, ra);
append ac to existing arrays;
end
function createArrayCombitations(la, ra)
foreach a in la
foreach b in ra
r = combineArrays(a,b);
add r to result;
end
end
end
function combineArrays(a, b)
generate all combinations of elements from two array such that order of elements in each array is preserved.
Ie if x precedes y in a or b the x precedes y in result

Find a path algorithm in a graph using java

I have to implement a search algorithm in java for a school project. In this algorithm i need to find, in an undirected graph, a path that goes through each link only once and ends in the start node. I'm trying to use a DFS with backtracking to solve this problem, but i'm having trouble implementating it. Here's my code:
import java.util.*;
public class Graph {
private Map<Integer, LinkedHashSet<Integer>> map =
new HashMap<Integer, LinkedHashSet<Integer>>();
private int startNode;
private int numLinks;
public Graph(int startNode, int numLinks) {
super();
this.startNode = startNode;
this.numLinks = numLinks;
}
public void addEdge(int source, int destiny) {
LinkedHashSet<Integer> adjacente = map.get(source);
if(adjacente==null) {
adjacente = new LinkedHashSet<Integer>();
map.put(source, adjacente);
}
adjacente.add(destiny);
}
public void addLink(int source, int destiny) {
addEdge(source, destiny);
addEdge(destiny, source);
}
public LinkedList<Integer> adjacentNodes(int last) {
LinkedHashSet<Integer> adjacente = map.get(last);
System.out.println("adjacentes:" + adjacente);
if(adjacente==null) {
return new LinkedList<Integer>();
}
return new LinkedList<Integer>(adjacente);
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int numVertices = input.nextInt();
int numLinks = input.nextInt();
int startNode = input.nextInt();
int endNode = startNode;
Graph mapa = new Graph(startNode, numLinks);
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
Integer currentNode = startNode;
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
mapa.findAllPaths(mapa, visited, paths, currentNode);
for(ArrayList<Integer> path : paths){
for (Integer node : path) {
System.out.print(node);
System.out.print(" ");
}
System.out.println();
}
}
private void findAllPaths(Graph mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
return;
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
The program is supposed to receive integers on his input, where the first one is the number of nodes, the second one is the number of links, the third is the start node(wich is also the end node), all the integers that come after represent the links between nodes.
The goal is to, in the end, print a single line with integers. This integers represent the order i visit each node to complete the path. Currently testing, it only prints a single integer, wich represents the first node.
I think my problem is either populating the graph, populating the adjacent list. Can somebody help me?
The problem is that when you call mapa.findAllPaths(mapa, visited, paths, currentNode);, you don't actually find all paths. You only find one path (i.e. the current node) and you return:
private void findAllPaths(Graph mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
return;// <--- WRONG!!!
} else {
// The else is never executed!
}
}
You should either have a loop or recursively call the findAllPaths until you find all the paths.
The first time you invoke the findAllPaths method you are passing the startNode as the last argument (the currentNode), which leads to currentNode.equals(startNode) being true and as such the only part of the method that gets executed is:
paths.add(new ArrayList<Integer>(visited));
return;
In essence, you only add the first node to your paths and then your algorithm finishes, thus always printing a single integer, the start node.

Find all paths in a graph with DFS

Good morning!
I'm developing an algorithm to find all the paths in an undirected, not weighted graph. I'm currently using a DFS algortihm with backtracking to try and do that. Here is my current code:
import java.util.*;
public class dfs {
private static Map<Integer, LinkedHashSet<Integer>> map = new HashMap<Integer, LinkedHashSet<Integer>>();
private int startNode;
private int numLinks;
public dfs(int startNode, int numLinks) {
super();
this.startNode = startNode;
this.numLinks = numLinks;
}
public void addEdge(int source, int destiny) {
LinkedHashSet<Integer> adjacente = map.get(source);
if(adjacente==null) {
adjacente = new LinkedHashSet<Integer>();
map.put(source, adjacente);
}
adjacente.add(destiny);
}
public void addLink(int source, int destiny) {
addEdge(source, destiny);
addEdge(destiny, source);
}
public LinkedList<Integer> adjacentNodes(int last) {
LinkedHashSet<Integer> adjacente = map.get(last);
System.out.println("adjacentes:" + adjacente);
if(adjacente==null) {
return new LinkedList<Integer>();
}
return new LinkedList<Integer>(adjacente);
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int numVertices = input.nextInt();
int numLinks = input.nextInt();
int startNode = input.nextInt();
int endNode = startNode;
dfs mapa = new dfs(startNode, numLinks);
for(int i = 0; i<numLinks; i++){
mapa.addLink(input.nextInt(), input.nextInt());
}
List<ArrayList<Integer>> paths = new ArrayList<ArrayList<Integer>>();
List<Integer> visited = new ArrayList<Integer>();
visited.add(startNode);
Integer currentNode = 0;
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
currentNode = (Integer) pairs.getKey();
//System.out.println("Current Node:" + currentNode);
mapa.findAllPaths(mapa, visited, paths, currentNode);
}
}
private void findAllPaths(dfs mapa, List<Integer> visited,
List<ArrayList<Integer>> paths, Integer currentNode) {
if (currentNode.equals(startNode)) {
paths.add(new ArrayList<Integer>(visited));
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
//System.out.println("visited:" + visited);
for (Integer node : nodes) {
//System.out.println("nodes:" + nodes);
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
else {
LinkedList<Integer> nodes = mapa.adjacentNodes(currentNode);
System.out.println("currentNode:" + currentNode);
//System.out.println("nodes:" + nodes);
for (Integer node : nodes) {
if (visited.contains(node)) {
continue;
}
List<Integer> temp = new ArrayList<Integer>();
temp.addAll(visited);
System.out.println("visited:" + visited);
temp.add(node);
findAllPaths(mapa, temp, paths, node);
}
}
}
}
The program receives integers on his input. The first one is the number of nodes, the second one is the number of links and the third is the start node and end note, which are the same. All the integers that come after represent the connections between nodes.
The problem is, this algorithm is finding all the paths that visit a single node only once. What i want is the algorithm to find all the paths that visit each connection only once.
Any idea on how i can do that?
You are on the right track - backtracking is a neat way to solve it.
To get all paths that "uses the same edge only once":
after you use an edge in findAllPaths() - delete it from the set of edges [delete the connection from the LinkedHashSet of each vertex of this edge] - and invoke recursively.
After you return from the recursion - don't forget to "clean up the environment" and add this edge back to both vertices.
You will need to make sure you don't run into troubles of iterating collection while modifying it. [You cannot do it - the result of doing so is unexpected] - so you will probably need to send a copy of the LinkedHashSets [without the relevant edge] - and not the original one.

Categories

Resources