Reading from text file to array of object in java - java

I am working on Dijkstra algorithm. The program that I have read the data from a text file. the program works fine if I input the relation in the program but it does not work when I try to read the input from text file.
the input to the program in the program itself is as following:
private static final Graph.Edge[] Arr = {
new Graph.Edge("a", "b", 1),
new Graph.Edge("a", "c", 1),
new Graph.Edge("a", "f", 1),
new Graph.Edge("b", "c", 1),
new Graph.Edge("b", "d", 1),
new Graph.Edge("c", "d", 1),
new Graph.Edge("c", "f", 1),
new Graph.Edge("d", "e", 1),
new Graph.Edge("e", "f", 1),
};
what I have tried to read from text file to be instead of this input is as following:
first, I count the number of the line to be the size of the array:
public static int count;
public static void countLines(String file) throws IOException
{
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(file)));
lnr.skip(Long.MAX_VALUE);
Dijkstra.count=lnr.getLineNumber() + 1;
lnr.close();
}
The function that will do the reading from the text file and saving the data to the array is as following:
public static Graph.Edge[] readTextFile(String fileName) {
String line = null;
Graph.Edge[] Gr=new Graph.Edge[Dijkstra.count-1];
try {
FileReader fileReader = new FileReader("txt2.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
int i=0;
while ((line = bufferedReader.readLine()) != null) {
String[] tokens = line.split("\\t+");
String s = tokens[0];
String e = tokens[2];
Gr[i] =new Graph.Edge(s, e, 1);
i=i+1;
}
bufferedReader.close();
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '" + fileName + "'");
} catch (IOException ex) {
System.out.println("Error reading file '" + fileName + "'");
}
return Gr;
}
these functions and the main are within some class called Dijkstra. the whole code is as following:
package shortestPath;
import java.util.Scanner;
import java.io.*;
import java.util.*;
public class Dijkstra {
/*private static final Graph.Edge[] Arr = {
new Graph.Edge("a", "b", 1),
new Graph.Edge("a", "c", 1),
new Graph.Edge("a", "f", 1),
new Graph.Edge("b", "c", 1),
new Graph.Edge("b", "d", 1),
new Graph.Edge("c", "d", 1),
new Graph.Edge("c", "f", 1),
new Graph.Edge("d", "e", 1),
new Graph.Edge("e", "f", 1),
};*/
public static int count;
//public static Graph.Edge[] GRAPH = new Graph.Edge[count] ;
public static void countLines(String file) throws IOException
{
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(file)));
lnr.skip(Long.MAX_VALUE);
Dijkstra.count=lnr.getLineNumber() + 1; //Add 1 because line index starts at 0
// Finally, the LineNumberReader object should be closed to prevent resource leak
lnr.close();
//return Dijkstra.count;
}
public static Graph.Edge[] readTextFile(String fileName) {
String line = null;
Graph.Edge[] Gr=new Graph.Edge[Dijkstra.count-1];
try {
FileReader fileReader = new FileReader("txt2.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
int i=0;
while ((line = bufferedReader.readLine()) != null) {
String[] tokens = line.split("\\t+");
String s = tokens[0];
String e = tokens[2];
Gr[i] =new Graph.Edge(s, e, 1);
i=i+1;
}
// Always close files.
bufferedReader.close();
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '" + fileName + "'");
} catch (IOException ex) {
System.out.println("Error reading file '" + fileName + "'");
}
//return Dijkstra.GRAPH;
return Gr;
}
private static final String START = "12";
private static final String END = "18";
public static void main(String[] args) throws IOException {
countLines("hsa00072.txt");
Graph.Edge[] GRAPH=readTextFile("hsa00072.txt");
Graph g = new Graph(GRAPH);
g.dijkstra(START);
g.printPath(END);
//g.printAllPaths();
}
}
class Graph {
private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges
/** One edge of the graph (only used by Graph constructor) */
public static class Edge {
public final String v1, v2;
public final int dist;
public Edge(String v1, String v2, int dist) {
this.v1 = v1;
this.v2 = v2;
this.dist = dist;
}
}
/** One vertex of the graph, complete with mappings to neighbouring vertices */
public static class Vertex implements Comparable<Vertex> {
public final String name;
public int dist = Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity
public Vertex previous = null;
public final Map<Vertex, Integer> neighbours = new HashMap<>();
public Vertex(String name) {
this.name = name;
}
private void printPath() {
if (this == this.previous) {
System.out.printf("%s", this.name);
} else if (this.previous == null) {
System.out.printf("%s(unreached)", this.name);
} else {
this.previous.printPath();
System.out.printf(" -> %s(%d)", this.name, this.dist);
}
}
public int compareTo(Vertex other) {
return Integer.compare(dist, other.dist);
}
}
/** Builds a graph from a set of edges */
public Graph(Edge[] edges) {
graph = new HashMap<>(edges.length);
//one pass to find all vertices
for (Edge e : edges) {
if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1));
if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2));
}
//another pass to set neighbouring vertices
for (Edge e : edges) {
graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
//graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
}
}
/** Runs dijkstra using a specified source vertex */
public void dijkstra(String startName) {
if (!graph.containsKey(startName)) {
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
return;
}
final Vertex source = graph.get(startName);
NavigableSet<Vertex> q = new TreeSet<>();
// set-up vertices
for (Vertex v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Integer.MAX_VALUE;
q.add(v);
}
dijkstra(q);
}
/** Implementation of dijkstra's algorithm using a binary heap. */
private void dijkstra(final NavigableSet<Vertex> q) {
Vertex u, v;
while (!q.isEmpty()) {
u = q.pollFirst(); // vertex with shortest distance (first iteration will return source)
if (u.dist == Integer.MAX_VALUE) break; // we can ignore u (and any other remaining vertices) since they are unreachable
//look at distances to each neighbour
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
v = a.getKey(); //the neighbour in this iteration
final int alternateDist = u.dist + a.getValue();
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
}
}
}
/** Prints a path from the source to the specified vertex */
public void printPath(String endName) {
if (!graph.containsKey(endName)) {
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
return;
}
graph.get(endName).printPath();
System.out.println();
}
/** Prints the path from the source to every vertex (output order is not guaranteed) */
public void printAllPaths() {
for (Vertex v : graph.values()) {
v.printPath();
System.out.println();
}
}
}
The text file is as following:
12 ECrel 15
15 ECrel 18
11 ECrel 12
12 ECrel 14
11 ECrel 14
11 ECrel 18
14 maplink 17
the problem is whenever I want to find the path like from node 12 to node 18 it will say 18(unreached) even if there is a path but it will not return the path. in case of the input in the program it works fine and return the path. the problem is only appears when trying to read from the text file.

There is something very strange going on here. I'll babble along as I work through it.
I get randomly different results (sometimes your program works as you wanted, sometimes not). Often they are different depending on whether I am running in debug mode or not.
So . . . it's time to look for a source of randomness. Clearly you're not using randomness directly/intentionally. So we should look somewhere else for the randomness.
I think I see two potential sources of randomness.
When you're traversing the NavigableSet, it's doing a lot of comparing equal values at first. That's necessary and makes sense, but it might lead to randomness, since it doesn't have to pick one particular order of how to present the elements to you.
You also use Maps in your algorithm, and there are no promises about what order their entrySets come back in.
My guess is that your algorithm is actually sensitive to the order in which things are presented to it. I haven't dug in enough to know which bits might be the problem, but maybe this section goes two different directions if two equally good routes are presented to it in different orders:
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
and possibly one of those routes never leads to the destination you're looking for.
I would actually suggest getting out bits of paper and writing the vertices on them, and shuffling them whenever your algorithm calls for an iterator over map EntrySets.
My suspicion for why this works when reading from the source and fails when reading from code: different random seeds. That's it. It's technically prone to the same failure in both cases, it just happens to pick a working path in one JVM scenario and a non-working path in the other JVM scenario.
Sorry this is kind of fuzzy and really long. Maybe it will help.

Related

How is a section of code affecting the algorithm?

Sorry if this a silly or wrong question, I found a solution in Java for short path algorithm. Here is the code:
import java.io.*;
import java.util.*;
public class Dijkstra {
private static final Graph.Edge[] GRAPH = {
new Graph.Edge("a", "b", 7),
new Graph.Edge("a", "c", 9),
new Graph.Edge("a", "f", 14),
new Graph.Edge("b", "c", 10),
new Graph.Edge("b", "d", 15),
new Graph.Edge("c", "d", 11),
new Graph.Edge("c", "f", 2),
new Graph.Edge("d", "e", 6),
new Graph.Edge("e", "f", 9),
};
private static final String START = "a";
private static final String END = "e";
public static void main(String[] args) {
Graph g = new Graph(GRAPH);
g.dijkstra(START);
g.printPath(END);
//g.printAllPaths();
}
}
class Graph {
private final Map<String, Vertex> graph; // mapping of vertex names to Vertex objects, built from a set of Edges
/** One edge of the graph (only used by Graph constructor) */
public static class Edge {
public final String v1, v2;
public final int dist;
public Edge(String v1, String v2, int dist) {
this.v1 = v1;
this.v2 = v2;
this.dist = dist;
}
}
/** One vertex of the graph, complete with mappings to neighbouring vertices */
public static class Vertex implements Comparable<Vertex> {
public final String name;
public int dist = Integer.MAX_VALUE; // MAX_VALUE assumed to be infinity
public Vertex previous = null;
public final Map<Vertex, Integer> neighbours = new HashMap<>();
public Vertex(String name) {
this.name = name;
}
private void printPath() {
if (this == this.previous) {
System.out.printf("%s", this.name);
} else if (this.previous == null) {
System.out.printf("%s(unreached)", this.name);
} else {
this.previous.printPath();
System.out.printf(" -> %s(%d)", this.name, this.dist);
}
}
public int compareTo(Vertex other) {
return Integer.compare(dist, other.dist);
}
}
/** Builds a graph from a set of edges */
public Graph(Edge[] edges) {
graph = new HashMap<>(edges.length);
//one pass to find all vertices
for (Edge e : edges) {
if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1));
if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2));
}
//another pass to set neighbouring vertices
for (Edge e : edges) {
graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist);
//graph.get(e.v2).neighbours.put(graph.get(e.v1), e.dist); // also do this for an undirected graph
}
}
/** Runs dijkstra using a specified source vertex */
public void dijkstra(String startName) {
if (!graph.containsKey(startName)) {
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
return;
}
final Vertex source = graph.get(startName);
NavigableSet<Vertex> q = new TreeSet<>();
// set-up vertices
for (Vertex v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Integer.MAX_VALUE;
q.add(v);
}
dijkstra(q);
}
/** Implementation of dijkstra's algorithm using a binary heap. */
private void dijkstra(final NavigableSet<Vertex> q) {
Vertex u, v;
while (!q.isEmpty()) {
u = q.pollFirst(); // vertex with shortest distance (first iteration will return source)
if (u.dist == Integer.MAX_VALUE) break; // we can ignore u (and any other remaining vertices) since they are unreachable
//look at distances to each neighbour
for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
v = a.getKey(); //the neighbour in this iteration
final int alternateDist = u.dist + a.getValue();
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
}
}
}
/** Prints a path from the source to the specified vertex */
public void printPath(String endName) {
if (!graph.containsKey(endName)) {
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
return;
}
graph.get(endName).printPath();
System.out.println();
}
/** Prints the path from the source to every vertex (output order is not guaranteed) */
public void printAllPaths() {
for (Vertex v : graph.values()) {
v.printPath();
System.out.println();
}
}
}
I understood most of this algorithm, but the method private void dijkstra(final NavigableSet<Vertex> q) confuses me by the following question:
How is it being evaluated by rest of the code, as it doesnt have any return method?
Is using NavigableSet / TreeSet better than using PriorityQueue?
And, also I have a question about compareTo method which is overriden in class Vertex, how is it being called?
Thanks
How is it being evaluated by rest of the code, as it doesn't have any return method?
The part that is specifically doing the evaluating is:
u = q.pollFirst();
The part that effects what q.pollFirst() returns is:
if (alternateDist < v.dist) { // shorter path to neighbour found
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
The v node gets removed from the set, it's distance is being updated, then it is re-added to the set.
The distance being updated is the most important part.
The node being removed then re-added is probably required so that the node is ordered by the new distance value rather than the old distance value.
The point of all that is so q.pollFirst() returns the node with the shortest distance.
Is using NavigableSet / TreeSet better than using PriorityQueue?
"better" is subjective. Are you looking for speed or a nicer interface, or a particular data structure?
From what I understand, both TreeSet and PriorityQueue uses Comparable to order nodes, so in that sense they work similarly.
Besides that, TreeSet is a set, so nodes can only exists once in the set, whereas, PriorityQueue is a queue and can have the same node inserted multiple times.
In this case, a set seems to work fine for the dijkstra algorithm.
How is the compareTo method which is overriden in class Vertex being called?
The compareTo function is used internally by the TreeSet to order the nodes as they are being added.
The new node is compared against the nodes already in the set. The Vertex#compareTo provides the algorithm to determine how two Vertex compare with one another. In this case, the distance value of the Vertex is compared.
This also hints as to why the nodes are removed and re-added to the set in the dijkstra(final NavigableSet<Vertex> q) function.
How is it being evaluated by rest of the code, as it doesnt have any return method?
The parameter of the method is a mutable container which is referenced by the parts of the algorithm.
final Vertex source = graph.get(startName);
NavigableSet<Vertex> q = new TreeSet<>();
// set-up vertices
for (Vertex v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Integer.MAX_VALUE;
q.add(v);
}
dijkstra(q);
Is using NavigableSet / TreeSet better than using PriorityQueue?
you can find answer in this question Difference between PriorityQueue and TreeSet in Java?
1) There are two methods with the same name:
public void dijkstra(String startName)
private void dijkstra(final NavigableSet<Vertex> q)
If you call dijkstra("a"), the first method will be called, and if you call diijkstra(q) where q is a NavigableSet<Vertex>, then the second method will be called.
2) This depends on the underlying data structure used to implement TreeSet and PriorityQueue, as well as the input Graph. For some input graphs, an unsorted array could perform faster than a min-heap.
3) I suspect it will be a requirement for objects added to NavigableSet to have a working compareTo() method so that NavigableSet can work it's magic.

How to optimize performance when repeatedly looping over a big list of objects

I have a simple file that contains two integer values per line (a source integer and a target integer). Each line represents a relation between two values. The file is not sorted and the actual file contains about 4 million lines. After sorting it may look like this:
sourceId;targetId
1;5
2;3
4;7
7;4
8;7
9;5
My goal is to create a new object that will represent all unique related integers in a list with a unique identifier. The expected output of this example should be the following three objects:
0, [1, 5, 9]
1, [2, 3]
2, [4, 7, 8]
So groupId 0 contains a group of relations (1, 5 and 9).
Below is my current way to create a list of these objects. The list of Relation objects contains all the lines in memory. And the list of GroupedRelation should be the end result.
public class GroupedRelationBuilder {
private List<Relation> relations;
private List<GroupedRelation> groupedRelations;
private List<String> ids;
private int frameId;
public void build() {
relations = new ArrayList<>();
relations.add(new Relation(1, 5));
relations.add(new Relation(4, 7));
relations.add(new Relation(8, 7));
relations.add(new Relation(7, 4));
relations.add(new Relation(9, 5));
relations.add(new Relation(2, 3));
// sort
relations.sort(Comparator.comparing(Relation::getSource).thenComparing(Relation::getTarget));
// build the groupedRelations
groupId = 0;
groupedRelations = new ArrayList<>();
for (int i = 0; relations.size() > 0;) {
ids = new ArrayList<>();
int compareSource = relations.get(i).getSource();
int compareTarget = relations.get(i).getTarget();
ids.add(Integer.toString(compareSource));
ids.add(Integer.toString(compareTarget));
relations.remove(i);
for (int j = 0; j < relations.size(); j++) {
int source = relations.get(j).getSource();
int target = relations.get(j).getTarget();
if ((source == compareSource || source == compareTarget) && !ids.contains(Integer.toString(target))) {
ids.add(Integer.toString(target));
relations.remove(j);
continue;
}
if ((target == compareSource || target == compareTarget) && !ids.contains(Integer.toString(source))) {
ids.add(Integer.toString(source));
relations.remove(j);
continue;
}
}
if (relations.size() > 0) {
groupedRelations.add(new GroupedRelation(groupId++, ids));
}
}
}
class GroupedRelation {
private int groupId;
private List<String> relatedIds;
public GroupedRelation(int groupId, List<String> relations) {
this.groupId = groupId;
this.relatedIds = relations;
}
public int getGroupId() {
return groupId;
}
public List<String> getRelatedIds() {
return relatedIds;
}
}
class Relation {
private int source;
private int target;
public Relation(int source, int target) {
this.source = source;
this.target = target;
}
public int getSource() {
return source;
}
public void setSource(int source) {
this.source = source;
}
public int getTarget() {
return target;
}
public void setTarget(int target) {
this.target = target;
}
}
}
When I run this small example program, it takes 15 seconds to create 1000 GroupedRelation objects. To create 1 million GroupedRelation it would take 250 minutes..
I am looking for help in optimizing my code that does get the result I want but simply takes to long.
Is it possible to optimize the iteration in such a way that the expected result is the same but the time it takes to get the expected result is reduced significantly? If this is possible, how would you go about it?
The current implementation is slow due to the ids.contains step.
The time complexity of the ArrayList.contains method is O(n):
to check if it contains an element it checks the elements one by one,
in the worst case scanning the entire list.
You can greatly improve the performance if you change the type of ids from List<String> to Set<String>, and use HashSet<String> instances.
The expected time complexity of Set.contains implementations is O(1),
significantly faster compared to a list.
As much as possible I would attempt to do it in a single pass from source.
import java.io.*;
import java.util.*;
/**
* Created by peter on 10/07/16.
*/
public class GroupedRelationBuilder {
public static List<List<Integer>> load(File file) throws IOException {
Map<Integer, Group> idToGroupMap = new HashMap<>();
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
br.readLine();
for (String line; (line = br.readLine()) != null; ) {
String[] parts = line.split(";");
Integer source = Integer.parseInt(parts[0]);
Integer target = Integer.parseInt(parts[1]);
Group grp0 = idToGroupMap.get(source);
Group grp1 = idToGroupMap.get(target);
if (grp0 == null) {
if (grp1 == null) {
Group grp = new Group();
List<Integer> list = grp.ids;
list.add(source);
list.add(target);
idToGroupMap.put(source, grp);
idToGroupMap.put(target, grp);
} else {
grp1.ids.add(source);
idToGroupMap.put(source, grp1);
}
} else if (grp1 == null) {
grp0.ids.add(target);
idToGroupMap.put(target, grp0);
} else {
grp0.ids.addAll(grp1.ids);
grp1.ids = grp0.ids;
}
}
}
Set<List<Integer>> idsSet = Collections.newSetFromMap(new IdentityHashMap<>());
for (Group group : idToGroupMap.values()) {
idsSet.add(group.ids);
}
return new ArrayList<>(idsSet);
}
static class Group {
List<Integer> ids = new ArrayList<>();
}
public static void main(String[] args) throws IOException {
File file = File.createTempFile("deleteme", "txt");
Set<String> pairs = new HashSet<>();
try (PrintWriter pw = new PrintWriter(file)) {
pw.println("source;target");
Random rand = new Random();
int count = 1000000;
while (pairs.size() < count) {
int a = rand.nextInt(count);
int b = rand.nextInt(count);
if (a < b) {
int t = a;
a = b;
b = t;
}
pairs.add(a + ";" + b);
}
for (String pair : pairs) {
pw.println(pair);
}
}
System.out.println("Processing");
long start = System.currentTimeMillis();
List<List<Integer>> results = GroupedRelationBuilder.load(file);
System.out.println(results.size() + " took " + (System.currentTimeMillis() - start) / 1e3 + " sec");
}
}
For one million pairs this prints
Processing
105612 took 12.719 sec
You implementation is slow due to the Integer.toString() usage.
Changing the type means object and memory allocations. This is now done 4-5 times in the subloop.
Changing it took me from 126ms to 35ms: 4 times faster!
Several other things I see are:
first for loop can be changed into while(!relations.isEmpty())
the second loop could be done by using an iterator for (Iterator<Relation> iterator = relations.iterator(); iterator.hasNext();). When you remove an item, you are now skipping the next.
Place the declaration of ids inside the loop

java.lang.NoSuchMethodError: Graph: method <init>()V not found

I'm getting a confusing error in eclipse but not on our main server from the command line linux account. All code is in the main src directory, in eclipse. Code compiles at command line but produces this error in Eclipse on my Mac OS X laptop:
Exception in thread "main" java.lang.NoSuchMethodError: Graph: method <init>()V not found
at Lab17.main(Lab17.java:11)
The code
Lab17.java
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;
public class Lab17 {
// Lab17 first attempt at creating a graph
public static void main(String[] args) throws Exception {
Graph myGraph = new Graph();
URLConnection conn = null;
try {
URL url = new URL("http://csc.mendocino.edu/~jbergamini/222data/flights/flights");
conn = url.openConnection();
} catch (IOException e) {
System.out.println("Unable to open Flights file");
System.exit(1);
}
Scanner s = null;
try {
s = new Scanner(conn.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (s.hasNext()) {
String src = s.next();
String dst = s.next();
s.next();
double cost = s.nextDouble();
//System.out.println(src+" "+dst+" "+cost);
myGraph.addEdge(src, dst, cost);
}
System.out.println(myGraph.breadthFirst("Austin", "Washington"));
System.out.println(myGraph.depthFirst("LosAngeles", "Washington"));
System.out.println(myGraph.breadthFirst("LosAngeles", "Washington"));
System.out.println(myGraph.depthFirst("Washington", "LosAngeles"));
System.out.println(myGraph.breadthFirst("Washington", "LosAngeles"));
}
}
Graph.java
import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeMap;
public class Graph {
private TreeMap<String, Vertex> vertexMap;
/** Creates a new, empty graph */
public Graph() {
// create vertexMap for Graph
vertexMap = new TreeMap<String, Vertex>();
}
/**
* Adds an edge
* #param src the source vertex
* #param dst the destination vertex
* #param cost the weight of the edge
*/
public void addEdge(String src, String dst, double cost) {
//System.out.println(src+" "+dst+" "+cost+" in Graph()");
// check to see if there is a src vertex
if(vertexMap.get(src) == null) {
// if src Vertex does not exist create Vertex for src
vertexMap.put(src, (new Vertex(src)));
//System.out.println(vertexMap.get(src).toString());
}
// check to see if there is a dst Vertex
if(vertexMap.get(dst) == null) {
// if dst Vertex does not exist create Vertex for dst
vertexMap.put(dst, (new Vertex(dst)));
//System.out.println(vertexMap.get(dst).toString());
}
// populate the dst and cost for Edge on the src Vertex vertexMap element
Vertex srdVertex = vertexMap.get(src);
Vertex dstVertex = vertexMap.get(dst);
Edge sEdge = new Edge(dstVertex, cost);
srdVertex.addEdge(sEdge);
}
/** Clears/empties the graph */
public void clear() {
vertexMap = new TreeMap<String,Vertex>();
}
/**
* Traverses, depth-first, from src to dst, and prints the vertex names in the order visited.
* #param src the source vertex
* #param dst the destination vertex
* #return whether a path exists from src to dst
*/
public boolean depthFirst(String src, String dst) {
System.out.println("Depth-first from "+src+" to "+dst);
for(Map.Entry<String,Vertex> entry: vertexMap.entrySet()) {
String key = entry.getKey();
Vertex thisVertex = entry.getValue();
System.out.println(key + " => " + thisVertex.toString());
}
return false;
}
/**
* Traverses, breadth-first, from src to dst, and prints the vertex names in the order visited
* #param src the source vertex
* #param dst the destination vertex
* #return whether a path exists from src to dst
*/
public boolean breadthFirst(String src, String dst) {
System.out.println("Breadth-first from "+src+" to "+dst);
// find starting vertex in vertexMap
Vertex start = vertexMap.get(src);
LinkedList<Vertex> vertexQue = new LinkedList<Vertex>();
LinkedList<Vertex> visitedV = new LinkedList<Vertex>();
// check it for null
if( start == null) {
throw new NoSuchElementException(" Start vertex not found");
}
// create a Queue for searching through vertex edges
//Queue<Vertex> q = new Queue<Vertex>();
vertexQue.add( start );
start.dest = 0;
boolean found = false;
while( !vertexQue.isEmpty() && !found) {
Vertex v = vertexQue.removeLast();
if( v.toString() == dst) {
// print queue
found = true;
}
else if(!visitedV.contains(v)){
// put all the adj vertex's into the queue
for( Edge e: v.getEdges() ) {
Vertex w = e.getDst();
vertexQue.add( w );
}
}
// add v to visitedV linked list
if(!visitedV.contains(v)){
visitedV.add(v);
}
}
System.out.print("[");
for(int i=0; i < visitedV.size(); i++) {
System.out.print(visitedV.get(i)+", ");
}
System.out.println("]");
/*forVertex> entry: vertexMap.entrySet()) {
String key = entry.getKey();
Vertex thisVertex = entry.getValue();
System.out.println(key + " => " + thisVertex.toString());
for(Edge e : thisVertex.getEdges() ){
System.out.print(e.toString());
}
System.out.println();
System.out.println("All Edges Evaluated");
}*/
return false;
}
}
Vertex.java
import java.util.Set;
import java.util.TreeSet;
public class Vertex {
private String name;
private TreeSet<Edge> adj;
public double dest;
/**
* Creates a new vertex
* #param name the name of the vertex
*/
public Vertex(String name) {
this.name = name;
adj = new TreeSet<Edge>();
}
public TreeSet<Edge> getEdges() {
return this.adj;
}
/**
* Returns the set of all edges starting from this vertex.
* Set shall be ordered with respect to the names of the destination vertices.
*/
public Set<Edge> allAdjacent() {
Set<Edge> vertexSet = adj;
return null;
}
public String toString() {
return name;
}
public void addEdge(Edge e) {
this.adj.add(e);
}
}
public class Edge implements Comparable<Edge> {
private Vertex dst;
private double cost;
/** Creates a new edge with an associated cost
* #param dst the destination vertex
* #param cost the weight of the edge
*/
public Edge(Vertex dst, double cost) {
this.dst = dst;
this.cost = cost;
}
public Vertex getDst() {
return dst;
}
#Override
public int compareTo(Edge o)
{
if(o == null)
return -1;
if(this == null)
return -1;
if( this.dst.toString().compareTo( ((Edge)o).dst.toString() ) == 0 )
return 0;
else if ( this.dst.toString().compareTo( ((Edge)o).dst.toString() ) < 0 )
return 1;
else
return -1;
}
public String toString() {
String theEdgeS = this.dst.toString()+" "+Double.toString(cost);
return theEdgeS;
}
}
Not sure why Eclipse environment is treating the code differently than the command-line environment is. The class's are a work in progress for a class. I'm only trying to solve what seems like an Eclipse bug.
It looks like the eclipse has an old version of Graph.class. You should try cleaning the project : See question Function of Project > Clean in Eclipse
Code compiles at command line but produces this error in Eclipse
Probable solutions :
1) Make sure the eclipse is using the same code as you use via command line.
2) Make a clean build inside eclipse because The case might be like it still referring the old class files regardless the thing that the source has been changed.
When you're running, Graph.class is not found in the classpath.

HashMap Java Cannot Display Multiple Values

Let me start by saying I have a file. For more info, you check it here.
I have already added the edges on the hashmap with multiple values. I have check it by adding this piece of code:
map.put(nodes.get(i), edges);
System.out.println(nodes.get(i) + " " + map.get(nodes.get(i)));
After adding each entry to map, I check it right away if it was successfully added. Yes, it worked.
Here's the output:
a0 [acodijkstra.Edge#b1c5fa]
a1 [acodijkstra.Edge#13caecd, acodijkstra.Edge#f84386, acodijkstra.Edge#1194a4e]
a2 [acodijkstra.Edge#15d56d5, acodijkstra.Edge#efd552, acodijkstra.Edge#19dfbff]
a3 [acodijkstra.Edge#10b4b2f, acodijkstra.Edge#750159, acodijkstra.Edge#1abab88]
But when creating another method to display the content of the map, I found out that the map is empty. Here's the code:
public void viewFile() {
for(int i=0; i<nodes.size();i++) {
System.out.println(nodes.get(i) + " " + this.map.get(nodes.get(i)));
}
}
The output of the above code is this:
a0 []
a1 []
a2 []
a3 []
What could be the possible reason for this? I am really confused why this happened.
For the code, here's the simplified version (if complied, this will result to errors since I edited some parts deemed unnecessary out):
class Reader {
HashMap<String, Vertex> vertexList;
Map<String, ArrayList<Edge>> map;
ArrayList<String> nodes;
ArrayList<Edge> edges;
public Reader(String fileName) {
vertexList = new HashMap<String, Vertex>();
map = new HashMap<String, ArrayList<Edge>>();
nodes = new ArrayList<String>();
edges = new ArrayList<Edge>();
readFile(fileName);
}
private void readFile(String fileName) {
try{
FileReader file = new FileReader(fileName);
Scanner sc = new Scanner(file);
int i = 0;
while (sc.hasNextLine()) {
input.add(sc.nextLine());
i++;
}
setNodes();
setVertices();
System.out.println();
file.close();
} catch(Exception e){
System.out.println(e);
}
}
public void setNodes() {
System.out.println();
for(int i=0; i<input.size(); i++) {
line = this.input.get(i);
nodes.add(line.substring(0,line.indexOf("-")).trim());
adjLine.add(line.substring(line.indexOf("-")+1).trim());
}
}
private void setVertices() {
String[] listEdges;
for(int i=0; i<nodes.size(); i++) {
//if vertex does not exist, create it
if(vertexList.containsKey(nodes.get(i))) {
vertexList.put(nodes.get(i), new Vertex(nodes.get(i)));
}
line = adjLine.get(i);
//separate adj edges to *
if(line.contains("*")) {
listEdges = line.split("\\*");
} else {
listEdges = new String[1];
listEdges[0] = line;
}
//add edges to specified vertex
for(int j=0; j < listEdges.length; j++ ) {
String[] word = listEdges[j].split(",");
edges.add(new Edge(vertexList.get(word[0]),Double.parseDouble(word[1])));
}
map.put(nodes.get(i), edges);
System.out.println(nodes.get(i) + " " + map.get(nodes.get(i)));
edges.clear();
}
}
Here:
map.put(nodes.get(i), edges);
System.out.println(nodes.get(i) + " " + map.get(nodes.get(i)));
edges.clear();
you're storing a reference to edges in the map, and then clearing edges. This is why, while the elements are still in the map, they are blank.
You need to stop reusing the same edges object, and create a new one for every vertex (why is edges even a member of your class, and not a local variable?)

File input for Dijkstra's algorithm

I am having trouble figuring out how to read an input file with java. The file has the following format:
u1 v1 w1
u2 v2 w2
...
um vm wm
-1
source
Each 3-tuple denotes an edge, which is specified by its source-vertex, its destination-vertex, and its weight (example: newyork boston 30). The description of the graph is terminated by a “flag”, the integer -1. A string follows this flag; this string is the name of the source vertex for the Dijkstra shortest-path algorithm. That is, you are to determine and print out the shortest path from this source vertex to every other vertex in the graph.
Here is my current work.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.PriorityQueue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
class Vertex implements Comparable<Vertex> {
public final String name;
public Edge[] adjacencies;
public double minDistance = Double.POSITIVE_INFINITY;
public Vertex previous;
public Vertex(String argName) {
name = argName;
}
public String toString() {
return name;
}
public int compareTo(Vertex other) {
return Double.compare(minDistance, other.minDistance);
}
}
class Edge {
public final Vertex target;
public final double weight;
public Edge(Vertex argTarget, double argWeight) {
target = argTarget;
weight = argWeight;
}
}
public class Dijkstra {
public static void computePaths(Vertex source) {
source.minDistance = 0.;
PriorityQueue<Vertex> vertexQueue = new PriorityQueue<Vertex>();
vertexQueue.add(source);
while (!vertexQueue.isEmpty()) {
Vertex u = vertexQueue.poll();
// Visit each edge exiting u
for (Edge e : u.adjacencies) {
Vertex v = e.target;
double weight = e.weight;
double distanceThroughU = u.minDistance + weight;
if (distanceThroughU < v.minDistance) {
vertexQueue.remove(v);
v.minDistance = distanceThroughU;
v.previous = u;
vertexQueue.add(v);
}
}
}
}
public static ArrayList<Vertex> getShortestPathTo(Vertex target) {
ArrayList<Vertex> path = new ArrayList<Vertex>();
for (Vertex vertex = target; vertex != null; vertex = vertex.previous)
path.add(vertex);
Collections.reverse(path);
return path;
}
public String[] readFile(String fileName) throws FileNotFoundException {
Scanner input = new Scanner(new File(fileName));
String line = "";
while (input.hasNext()) {
line = line.concat(input.nextLine());
}
String[] graph = line.split("");
return graph;
}
public static void main(String[] args) throws FileNotFoundException {
final String TEST = "/TestInput.txt";
Scanner input = new Scanner(new File(TEST));
String line = "";
while (input.hasNext()) {
line = line.concat(input.nextLine());
}
String[] graph = line.split(" ");
for (int i = 0; i < graph.length; i++) {
System.out.println(graph[i]);
}
Vertex[] verts = new Vertex[graph.length];
Edge[] edges = new Edge[graph.length];
Vertex v1 = new Vertex("");
Vertex v2 = new Vertex("");
Vertex source = new Vertex("");
int count = 0;
outerloop: for (int i = 0; i < (graph.length); i++) {
if (graph[i].equals("-1")) {
// do algorithm initialization here w/ source
}
if (i == 0) {
verts[i] = new Vertex(graph[i]);
count++;
} else {
innerloop: for (int j = count; j >= 0; j--) {
if (i / 3 == 0) {
if (graph[i].equals(verts[j].toString())) {
break innerloop;
} else if (j == 0) {
verts[count] = new Vertex(graph[i]);
v1 = verts[count];
count++;
}
}
if (i / 3 == 1) {
if (graph[i].equals(verts[j])) {
break innerloop;
} else if (j == 0) {
verts[count] = new Vertex(graph[i]);
v2 = verts[count];
count++;
}
}
if (i / 3 == 2) {
}
}
}
}
for (int i = 0; i < verts.length; i++) {
System.out.println(verts[i]);
}
}
}
So my only problem is how to get from the given .txt file format to a graph. Any suggestions are welcome.
Use a Scanner to parse the file data. For each tuple, if the source vertex hasn't been created, create it, otherwise find it in the pre-existing graph -- create a search function. Do the same for the target vertex. Next, create an edge with a weight equal to the third token in the tuple, and add the target vertex to the edge. Finally, add the edge to the adjacency list of the source vertex.
For the previously mentioned search function, you can implement something that can search through each vertex of the graph starting from any vertex. Recursion will be necessary.
public static Vertex search(Vertex src, String name);
A simpler solution is to keep a list of all the vertices you create as your constructing the graph and search through that.
public static Vertex search(List<Vertex> vertices, String name);
When your done constructing the graph and you have the name of the vertex where Dijkstra's algorithm will begin, you can use the search function to get a reference to the vertex.
Dijkstra.computePath(search(vertices, startVertexName));
And, that's it. Here's an example of how to parse your file data:
List<Vertex> vertices = new ArrayList<Vertex>();
String src =
"Pittsburgh Philadelphia 323 "+
"Pittsburgh Ohio 125 "+
"Ohio Philadelphia 400 "+
"-1 Ohio";
//new Scanner(new File(fileName));
Scanner scnr = new Scanner(src);
String src, target;
int weight;
while(scnr.hasNext())
{
src = scnr.next();
if(src.equals("-1"))
break;
else {
target = scnr.next();
weight = scnr.nextInt();
}
//call search(), implement logic in addToGraph()
addVertexToGraph(src, target, weight, vertices);
}
String startVertexName = scnr.next();
scnr.close();
Note that Scanner.next returns the next token separated by white space (the default delimiter), so your file data must be formatted that way.
Here's a shot:
/**
* Read the file using provided filename, construct vertices etc.
*
* #param fileName name of the file to read.
* #return true if everything is OK
* #throws FileNotFoundException if file is not found or not readable
*/
public boolean readFile(final String fileName) throws FileNotFoundException {
final Scanner input = new Scanner(new File(fileName));
boolean result = false;
while (input.hasNext()) {
final String line = line = input.nextLine();
if ("-1".equals(line)) {
// end of data
if (input.hasNext()) {
final String nameOfTheSource = input.next();
// TODO: do something with nameOfTheSource
result = true;
} else {
// bad input format: there should be something after -1
}
} else {
final String Scanner vert = new Scanner(line);
try {
final String sourceName = vert.next();
final String targetName = vert.next();
final int weight = vert.nextInt(); // assuming int for weight
// TODO: create Vertices and Edge here
} catch (final NoSuchElementException ex) {
// bad input format for "line"!
}
}
}
return result;
}
Not tested.
{import Stack.Dijkstra;
{import java.io.File;
{import java.io.FileNotFoundException;
{import java.util.Scanner;
{public class App {
{public static void main(String[] args) throws {FileNotFoundException {
{Vertex v1 = new Vertex("A");
{Vertex v2 = new Vertex("B");
{Vertex v3 = new Vertex("C");
{`v1.addNeighbour(new Edge(1, v1, v2));
{`v1.addNeighbour(new Edge(10, v1, v2));
{`v2.addNeighbour(new Edge(1, v2, v3));
{`Dijkstra dijkstra = new Dijkstra();
{`dijkstra.computePath(v1);
{`System.out.println(dijkstra.getShortestPathTo(v3));
{`final String test = "X:\\neon3\\eclipse\\TestInput.txt";
{`Scanner input = new Scanner(new File(test));
{`String line = "";
{`while (input.hasNext()) {
{`line = line.concat(input.nextLine());
}
{`String[] graph = line.split(" ");
{`for (int i = 0; i < graph.length; i++) {
{`System.out.println(graph[i]);
}
}
}`}

Categories

Resources