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.
I am doing a Breadth First Search program that will read in an adjacency list type text file, then perform BFS on it accordingly. I am having trouble reading in the text file, then adding it as an array list of nodes.
How would I get it to correctly read each line and associate the connections for it?
I have tested my program by manually adding Nodes within my main, then making a graph and performing BFS on it.
Here is my Node class:
import java.util.*;
public class Node {
public String data; // data element
public boolean visited=false; // flag to track the already visited node
public List<Node> adjacentNodes = new LinkedList<Node>(); // adjacency list
// public List adjacentNodes = new LinkedList(); // adjacency list
public Node rootNode;
public Node(String data){
this.data = data;
}
public void addAdjacentNode(final Node node){
adjacentNodes.add(node);
node.adjacentNodes.add(this);
// adjacentNodes.add(rootNode);
// node.adjacentNodes.add(this)
}
}
And here is my Graph class: (Where I attempted to read in my text file is within my main)
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.*;
/*- enqueue the start node to a Queue
- make the start node as visited
- while queue is not empty
- dequeue the node lets say u
- print or whatever you want to
- for every adjacent node v of u
- if v is not already visited
- mark v as visited
- enqueue v to the Queue*/
public class Graph {
public List nodes = new ArrayList();
public void breadthFirstTraversal(Node rootNode){
Queue<Node> q = new LinkedList<Node>();
// Queue q = new LinkedList();
q.add(rootNode);
System.out.print(rootNode.data + " ");
// printNode(rootNode);
rootNode.visited=true;
while(!q.isEmpty()){
Node n = (Node)q.poll();
System.out.print(n.data + " ");
for(Node adj : n.adjacentNodes){
if(!adj.visited){
adj.visited=true;
q.add(adj);
}
}
clearNodes();
}
}
private void clearNodes() {
// TODO Auto-generated method stub
nodes = null; //clear nodes and set to null
}
/* private void printNode(Node node) {
// TODO Auto-generated method stub
System.out.print(node);
}*/
public static void main(String[] args) throws FileNotFoundException {
Graph g = new Graph();
Scanner scan = new Scanner(new File("Connections.txt")); // scanner to read file
String line = scan.nextLine(); // read first line
int nbLine = Integer.parseInt(line); // get number of lines
ArrayList<int[]> al = new ArrayList<int[]>();
for(int i = 0; i < nbLine; i++) { // read each line
line = scan.nextLine();
String[] token = line.split(" "); // split each number into different String
int[] points = new int[token.length - 1]; // prepare array of int[] - 1
// int[] point = new int[];
int[] point = new int[token.length];
for(int j = 0; j < token.length; j++){ // skip first one
points[j-1] = Integer.parseInt(token[j]); // store as int
al.add(points); // save in ArrayList
}
/* Scanner s = new Scanner(new File("C:/Users/cantuj3/Documents/Ass 2/Connections.txt"));
ArrayList<Node> list = new ArrayList<Node>();
while (s.hasNext()){
g.nodes.add(s.next());
//list.add(g);
}
s.close();*/
/* Node frankfurt = new Node("frankfurt");
Node mannheim = new Node("mannheim");
Node wurzburg = new Node("wurzburg");
Node stuttgard = new Node("stuttgard");
Node kassel = new Node("kassel");
Node karlsruhe = new Node("karlsruhe");
Node erfurt = new Node("erfurt");
Node numberg = new Node("numberg");
Node augsburg = new Node("augsburg");
Node munchen = new Node("munchen");
Graph g = new Graph();
g.nodes.add(frankfurt);
g.nodes.add(mannheim);
g.nodes.add(wurzburg);
g.nodes.add(stuttgard);
g.nodes.add(kassel);
g.nodes.add(karlsruhe);
g.nodes.add(erfurt);
g.nodes.add(numberg);
g.nodes.add(augsburg);
g.nodes.add(munchen);
frankfurt.addAdjacentNode(mannheim);
frankfurt.addAdjacentNode(wurzburg);
frankfurt.addAdjacentNode(kassel);
mannheim.addAdjacentNode(karlsruhe);
karlsruhe.addAdjacentNode(augsburg);
augsburg.addAdjacentNode(munchen);
munchen.addAdjacentNode(kassel);
munchen.addAdjacentNode(numberg);
wurzburg.addAdjacentNode(erfurt);
wurzburg.addAdjacentNode(numberg);
numberg.addAdjacentNode(stuttgard);
g.breadthFirstTraversal(frankfurt);*/
}
}
Here is my input file:
01 02
02 01 03
03 02 04 05
04 03
05 03 06
06 05
Here is that chunk of code I wrote in my main by itself:
Scanner scan = new Scanner(new File("Connections.txt")); // scanner to read file
String line = scan.nextLine(); // read first line
int nbLine = Integer.parseInt(line); // get number of lines
ArrayList<int[]> al = new ArrayList<int[]>();
for(int i = 0; i < nbLine; i++) { // read each line
line = scan.nextLine();
String[] token = line.split(" "); // split each number into different String
int[] points = new int[token.length - 1]; // prepare array of int[] - 1
// int[] point = new int[];
int[] point;
for(int j = 0; j < token.length; j++){ // skip first one
points[j-1] = Integer.parseInt(token[j]); // store as int
al.add(points); // save in ArrayList
}
Am I on the right track?
Your basic steps will need to be:
Read a line of the file
Turn that line into an object
Add that object to a collection
Repeat until you have no more lines to read
Since I don't want to do your work for you, I'll leave you with some samples:
Read a line of the file
String line = reader.readLine(); // in this case, 'reader' will be a BufferedReader referencing your file
Turn that line into an object
This depends on what your input file format looks like. As an example, if my input is something like this:
first_thing 10
second_thing 20
third_thing 30
...
then I could do:
String[] components = line.split(" ");
if (components.length == 2) {
MyCustomObject myCustomObject = new MyCustomObject(components[0], components[1]);
}
Add that object to a collection
String[] components = line.split(" ");
if (components.length == 2) {
MyCustomObject myCustomObject = new MyCustomObject(components[0], components[1]);
myCollection.add(myCustomObject); // you can choose the type of collection here
}
Repeat until you have no more lines to read
while ( (line = reader.readLine()) != null ) {
...
}
Hope this helps!
i have this simple method:
public static Map<String, ArrayList<String>> szamolando = new HashMap<String,ArrayList<String>>();
ArrayList<String> outputs = new ArrayList<String>();
for(int i = 0;i<2;i++){
tombFeltolt("a"+i);
}
public void tombFeltolt(String kimenet) {
outputs.clear();
System.out.println("1");
outputs.add(min);
System.out.println("2");
outputs.add(max);
System.out.println("3");
outputs.add("65535");
szamolando.put(kimenet, outputs);
}
than i've got this output: 1 2 3 2
why do i got this?What is wrong with my method?Thank You for your answers!
Edit:
okay here is the complete code:
public static Map<String, ArrayList<String>> szamolando = new HashMap<String, ArrayList<String>>();
static ArrayList<String> outputs = new ArrayList<String>();
static String min, max;
public static void main(String[] args) {
for (int i = 0; i < 2; i++) {
if (i == 0) {
min = "10";
max = "20";
} else {
min = "9";
max = "8";
}
tombFeltolt("a" + i);
}
for (String name : szamolando.keySet()) {
String key = name.toString();
String value = szamolando.get(name).toString();
System.out.println("ASS " + key + " " + value);
}
}
public static void tombFeltolt(String kimenet) {
outputs.clear();
System.out.println("1");
outputs.add(min);
System.out.println("2");
outputs.add(max);
System.out.println("3");
outputs.add("65535");
szamolando.put(kimenet, outputs);
}
and here is my output:
ASS a0 [9, 8, 65535]
ASS a1 [9, 8, 65535]
you have to change this:
static ArrayList<String> outputs = new ArrayList<String>();
to this:
static ArrayList<String> outputs = null;
and put this line into your 'for' loop:
outputs = new ArrayList<String>();
This is the source of your problem
When you do a clear, it will clear the ArrayList which still references to the existing ArrayList which will clear the stored list as well coz it has stored the reference.
if you want 10, 20, 65535 use new list everytime.
outputs.clear();
I want to read data from a file and construct a graph from it. I did everything, all vertices are created normally, but when I add them to the graph, their adjacent lists (which are maps, whose key value is adjacent vertex's number, and value is their distance) become empty. Can anyone, please, tell what's the problem with my code?
public class Vertex {
private int number;
private LinkedHashMap<Integer, Integer> adjacent;
public Vertex(int num) {
this.number = num;
this.adjacent = new LinkedHashMap<Integer, Integer>();
}
}
public class Graph {
private ArrayList<Vertex> vertices;
private int verticesSize = 201;
public Graph() {
Vertex initialVertex = new Vertex(0);
this.vertices = new ArrayList<Vertex>();
for(int i = 0; i < verticesSize; i++) {
vertices.add(i, initialVertex);
}
}
}
public class Test {
public static void printGraph(Graph graph) {
for(int i = 0; i < graph.getVerticesSize(); i++)
System.out.println(graph.getVertices().get(i));
}
public static void main(String[] args) throws IOException {
FileInputStream fStream = new FileInputStream("C:/Lusine/Programming/Java/dijkstraData.txt");
// Use DataInputStream to read binary NOT text.
BufferedReader bReader = new BufferedReader(new InputStreamReader(fStream));
Graph graph = new Graph();
String[] maps;
String line;
LinkedHashMap<Integer, Integer> currentMap = new LinkedHashMap<Integer, Integer>();
while( (line = bReader.readLine()) != null) {
maps = line.split("\t");
int firstDigit = Integer.parseInt(maps[0]);
Vertex v = new Vertex(firstDigit);
for(int i = 1; i < maps.length; i++) {
String[] vertexDistance = maps[i].split(",");
int vertex = Integer.parseInt(vertexDistance[0]);
int distance = Integer.parseInt(vertexDistance[1]);
currentMap.put(vertex, distance);
}
v.setAdjacent(currentMap);
graph.getVertices().set(firstDigit, v);
System.out.println("\n" + firstDigit +"-th vertex is\n" + v);
currentMap.clear();
}
printGraph(graph);
}
when I print v, it's ok, but when I print graph, all adjacent lists are empty. What's the problem?
Your loop boils down to
LinkedHashMap<Integer, Integer> currentMap = new LinkedHashMap<Integer, Integer>();
while ( ... ) {
Vertex v = new Vertex(...);
v.setAdjacent(currentMap);
currentMap.clear();
}
So, you're storing the same map of adjacent vertices in every vertex, and you clear this map at the end of each iteration. So obviously, all the vertices share the same, empty map, at the end of the loop.
You should create a new LinkedHashMap at every iteration:
while ( ... ) {
LinkedHashMap<Integer, Integer> currentMap = new LinkedHashMap<Integer, Integer>();
Vertex v = new Vertex(...);
v.setAdjacent(currentMap);
}
And you should not clear it, cince clearing it, well... clears it.
import java.io.*;
import java.util.*;
class StepfordHouses {
private ArrayList<Integer> houses; // A list containing houses
private TreeSet<Integer> ordered; // An ordered treeset of houses
private TreeSet<Integer> processed; // Elements already processed
private String inpline[]; // An array of String holing houses heights in physical order
private int disorientedindex; // The index for the Street
private int size; // Number of houses in the Street
public StepfordHouses() // Constructor for init
{
houses = new ArrayList<Integer>();
ordered = new TreeSet<Integer>();
processed = new TreeSet<Integer>();
// Basic Input from Text-File (Codechef Requirment)
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
System.in));
size = Integer.parseInt(br.readLine());
inpline = br.readLine().split(" ");
} catch (IOException e) {
System.out.println("BAAAAAAAAAM!!");
}
for (int c = 0; c < size; c++) // Populating Houses
{
Integer tmp = Integer.parseInt(inpline[c]);
houses.add(tmp);
ordered.add(tmp);
}
}
public int calcIndex()
{
int c = 0;
while (c < size) {
Iterator<Integer> it = ordered.iterator();
Integer h1 = houses.get(c); // Get an element from the raw ArrayList of Houses
Integer h = it.next(); // Get an element from the Iterator
while (h1.equals(h) != true) {
if (processed.contains(h1) == false) { // The element is not already processed
System.out.println(h1 + " " + h);
disorientedindex++;
}
h = it.next(); // Get an element from the Iterator
}
processed.add(h1);
c++;
it = null;
}
return disorientedindex;
}
}
public class Work {
public static void main(String args[]) {
StepfordHouses sh = new StepfordHouses();
System.out.println(sh.calcIndex());
}
}
The contains() method doesn't work the way I expect it to, i.e compare Integers!
The output is 15 , which should be 9 when
if(processed.contains(h1)==false) works correctly and returns true when an element is already present!
Where could the code be wrong?
The logic is flawed. processed.add(h1); is called N times but processed.contains(h1) is called N*N times. So depending on the input you can have disorientedindex <> N.