I'm back with another question about my Dijkstra algorithm. I fixed my previous question, but now I want to make a toString() method.
When I try to make it, the variables I use are unreachable from toString(), and I don't understand why.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.ArrayList;
public class Graph
{
ArrayList<Vertex> vertexObjects = new ArrayList<Vertex>();
ArrayList<Edge> edgeObjects = new ArrayList<Edge>();
ArrayList<Vertex> visitedObjects = new ArrayList<Vertex>();
ArrayList<Vertex> unvisitedObjects = new ArrayList<Vertex>();
ArrayList<Edge> tempEdge = new ArrayList<Edge>();
int numVertices = 0;
public void readFile(String textfile)
{
try {
Scanner s = new Scanner(new File(textfile));
String sameVertex = "";
while (s.hasNext()) {
String preVertex = s.next();
String postVertex = s.next();
String distance = s.next();
Edge temp = new Edge(preVertex, postVertex, distance);
edgeObjects.add(temp);
if (!(preVertex.equals(sameVertex)))
{
Vertex herp = new Vertex(preVertex, Double.POSITIVE_INFINITY, false, null);
vertexObjects.add(herp);
sameVertex = preVertex;
numVertices++;
}
}
} catch (FileNotFoundException e) {
System.out.println("I can't find that file!");
}
}
public void dijkstra(String startVertex, String endVertex)
{
// Change the distance of the startVertex to 0 and all others to infinity.
for (int i = (numVertices-1); i >= 0; i--)
{
if (vertexObjects.get(i).vertexName.equals(startVertex))
{
vertexObjects.get(i).distance = 0;
} else {
vertexObjects.get(i).distance = Double.POSITIVE_INFINITY;
}
}
//Set the node with lowest distance value to Current Status
unvisitedObjects = vertexObjects;
double smallDistance = Double.POSITIVE_INFINITY;
while(unvisitedObjects.size() != 0) {
//set current node to vertex with shortest distance
String currentNode = "";
for (int j = (unvisitedObjects.size()-1); j >= 0; j--) {
if (unvisitedObjects.get(j).distance <= smallDistance) {
smallDistance = unvisitedObjects.get(j).distance;
currentNode = unvisitedObjects.get(j).vertexName;
}
}
//remove the smallest distance having node from the unvisited array
//and place into visited array.
for (int g = (unvisitedObjects.size()-1); g >= 0; g--) {
if (unvisitedObjects.get(g).vertexName.equals(currentNode))
{
visitedObjects.add(unvisitedObjects.get(g));
unvisitedObjects.remove(g);
}
}
//for all the nodes that are adjacent to the current node, update their
//distance values if they are larger than the weight plus previous distances.
for (int w = (edgeObjects.size()-1); w >= 0; w--) {
if (edgeObjects.get(w).startVertex == currentNode) {
tempEdge.add(edgeObjects.get(w));
}
for (int t = (tempEdge.size()-1); t >=0; t--) {
for (int p = (vertexObjects.size()-1); p >= 0; p--) {
if (tempEdge.get(t).endVertex == vertexObjects.get(p).vertexName)
{
if ((Double.parseDouble(tempEdge.get(t).edgeWeight) + smallDistance) < vertexObjects.get(p).distance) {
vertexObjects.get(p).distance = (Double.parseDouble(tempEdge.get(t).edgeWeight) + smallDistance);
}
}
}
}
}
}
String smallDString = Double.toString(smallDistance);
}
public Graph(String textfile, String startingVertex, String endingVertex) {
String graphFile = textfile;
String startVertex = startingVertex;
String endVertex = endingVertex;
}
public String toString() {
return ("The shortest path from "+startVertex+" to "+endVertex+" is "+smallDistance+".");
}
}
You can't access them because they are initialized within a function. You need to declare them as global variables.
ArrayList<Vertex> vertexObjects = new ArrayList<Vertex>();
ArrayList<Edge> edgeObjects = new ArrayList<Edge>();
ArrayList<Vertex> visitedObjects = new ArrayList<Vertex>();
ArrayList<Vertex> unvisitedObjects = new ArrayList<Vertex>();
ArrayList<Edge> tempEdge = new ArrayList<Edge>();
int numVertices = 0;
String startVertex, smallDistance, endVertex = "";
that might be the problem.
You need to make them field in your class. Not just local variables. For example in your constructor you can do:
private String graphFile; // declare variable to store value
public Graph(String textfile, String startingVertex, String endingVertex) {
graphFile = textfile; // assign value in constructor
...
You've only declared the variables in the public Graph(...) constructor, not in the scope for the rest of the class.
You need to declare them in the class body (normally near the top) for the methods to have access to them.
This is because you declared and initialized the variables (graphFile,startVertex,endVertex,) inside of your constructor. This means that they are only visible/usable inside the constructor. You need to declare them as class variables, then you can initialize them in the constructor. For example
public class Graph {
String graphFile;
public Graph(String textfile) {
this.graphFile = textfile;
}
}
You can do the same for the others as well.
Related
I made a adjacency matrix for cities and connecting between them. And for example A-B, B-C, C-D. Now I am wonder if I can calculate distance between cities that aren't connected. Is it possible to calculate distance in matrix between non connected nodes and find path?
Cities class
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class GraphCities {
private List<String> cities;
private int[][] matrix;
Scanner s = new Scanner(System.in);
public GraphCities() {
this.cities = new LinkedList<String>();
}
public void addCity(String name) {
if (!cities.contains(name)) {
cities.add(name);
} else {
System.out.println("City " + name + " is already added.");
}
}
public void makeGraph() {
System.out
.println("Distance between cities, if they aren't connected insert -1");
matrix = new int[cities.size()][cities.size()];
for (int i = 0; i < matrix.length; i++) {
for (int j = i; j < matrix.length; j++) {
if (i == j) {
matrix[i][j] = 0;
} else {
System.out.println("Distance from "
+ cities.get(i) + " to " + cities.get(j));
int distance = s.nextInt();
matrix[i][j] = distance;
matrix[j][i] = distance;
}
}
}
}
public void show() {
String show = "\t";
for (int i = 0; i < cities.size(); i++) {
show += cities.get(i) + "\t";
}
show += "\n";
for (int i = 0; i < matrix.length; i++) {
show += cities.get(i) + "\t";
for (int j = 0; j < matrix.length; j++) {
if (matrix[i][j] != -1) {
show += matrix[i][j] + "\t";
} else {
show += "-\t";
}
}
show += "\n";
}
System.out.println(show);
}
}
Main method
public class Main {
public static void main(String[] args) {
GraphCities c = new GraphCities();
c.addCity("A");
c.addCity("B");
c.addCity("C");
c.addCity("D");
c.addCity("E");
c.makeGraph();
System.out.println();
c.show();
}
}
This is my output when i run main method and i think everything is ok.
A B C D E
A 0 50 - - -
B 50 0 30 - -
C - 30 0 40 -
D - - 40 0 20
E - - - 20 0
Now I want to calculate distance from A to D, but i haven't any idea how to do it. I will appreciate any help. Thanks!
To find the shortest path in a weighted graph (each part of the route has a different weight) you can use Dijkstra's Shortest Path Algorithm.
The following code is a one-file mcve. It can be copy-pasted into one file (Main.java) , and executed.
(This answer is base on the code posted before editing the question)
Please note the comments:
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] args) {
AdjList aList = new AdjList();
CityNode a = new CityNode("A");
CityNode b = new CityNode("B");
CityNode c = new CityNode("C");
CityNode d = new CityNode("D");
CityNode e = new CityNode("E");
aList.addCity(a);
aList.addCity(b);
aList.addCity(c);
aList.addCity(d);
aList.addCity(e);
aList.connectCities(a, b, 50);
aList.connectCities(b, c, 30);
aList.connectCities(c, d, 40);
aList.connectCities(d, e, 20);
aList.show();
FindPath findPath = new FindPath();
System.out.println(findPath.calculateShortestPath(aList, a, e)); //prints 140 as expected
//add some complexity
CityNode f = new CityNode("F");
aList.addCity(f);
aList.connectCities(b, f, 10);
aList.connectCities(f, d, 10);
System.out.println(findPath.calculateShortestPath(aList, a, e));//prints 90 as expected
}
}
class FindPath{
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
Map<CityNode, Integer> distances;
//using Dijkstra algorithm
public int calculateShortestPath(AdjList aList, CityNode from, CityNode to) {
//a container to hold which cities the algorithm has visited
Set<CityNode> settledCities = new HashSet<>();
//a container to hold which cities the algorithm has to visit
Set<CityNode> unsettledCities = new HashSet<>();
unsettledCities.add(from);
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
distances = new HashMap<>();
//initialize map with values: 0 distance to origin, infinite distance to all others
//infinite means no connection between nodes
for(CityNode city :aList.getCities()){
int distance = city.equals(from) ? 0 : Integer.MAX_VALUE;
distances.put(city, distance);
}
while (unsettledCities.size() != 0) {
//get the unvisited city with the lowest distance
CityNode currentCity = getLowestDistanceCity(unsettledCities);
//remove from unvisited, add to visited
unsettledCities.remove(currentCity); settledCities.add(currentCity);
Map<CityNode, Integer> connectedCities = currentCity.getConnectedCities();
for( CityNode city : connectedCities.keySet()){
//check if new distance is shorted than the previously found distance
if(distances.get(currentCity) + connectedCities.get(city) < distances.get(city)){
//if so, keep the shortest distance found
distances.put(city, distances.get(currentCity) + connectedCities.get(city));
//if city has not been visited yet, add it to unsettledCities
if(! settledCities.contains(city)) {
unsettledCities.add(city);
}
}
}
}
return distances.get(to);
}
private CityNode getLowestDistanceCity(Set <CityNode> unsettledCities) {
return unsettledCities.stream()
.min((c1,c2)-> Integer.compare(distances.get(c1), distances.get(c2)))
.orElse(null);
}
}
class CityNode {
private static int counter =0;
private final String name;
//assign unique id to each node. safer than to rely on unique name
private final int id = counter ++;
//map to hold all connected cities and distance to each
private final Map<CityNode, Integer> connectedCities;
public CityNode(String name) {
super();
this.name = name;
connectedCities = new HashMap<>();
}
public String getName() {
return name;
}
//not null safe. distance must not be negative
public void connect(CityNode connectTo, int distance) {
if(connectTo.equals(this)) throw new IllegalArgumentException("Node can not connect to istself");
connectedCities.put(connectTo, distance);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder(name);
sb.append(connectedCities.keySet().isEmpty() ? " not connected" : " conntected to: " );
for ( CityNode city : connectedCities.keySet()) {
sb.append(city.getName()).append("-")
.append(connectedCities.get(city)).append("km ");
}
return sb.toString();
}
public int getId() {
return id;
}
public Map<CityNode, Integer> getConnectedCities(){
return connectedCities;
}
#Override
public boolean equals(Object o) {
if(o == null ||!(o instanceof CityNode)) return false;
CityNode c = (CityNode) o;
return c.getName().equalsIgnoreCase(name) && id == c.getId();
}
#Override
public int hashCode() {
int hash = 31 * 7 + id;
return name == null ? hash : name.hashCode();
}
}
class AdjList {
//use set which prevents duplicate entries
private final Set<CityNode> citiesList;
public AdjList() {
citiesList = new HashSet<>();
}
//adds city if is not already present. returns true if city was added
public boolean addCity(CityNode city) {
return citiesList.add(city);
}
//not null safe
public void connectCities(CityNode city1, CityNode city2, int distance) {
//assuming undirected graph
city1.connect(city2, distance);
city2.connect(city1, distance);
}
public CityNode getCityByName(String name) {
for (CityNode city : citiesList) {
if (city.getName().equalsIgnoreCase(name))
return city;
}
return null;
}
public void show() {
for (CityNode city : citiesList) {
System.out.println(city);
}
}
//get a copy of cities list
public Collection<CityNode> getCities(){
return new ArrayList<>(citiesList);
}
}
If you need a version of getLowestDistanceCity which does not use Stream use :
private CityNode getLowestDistanceCity(Set <CityNode> unsettledCities) {
CityNode lowestDistanceCity = null;
int lowestDistance = Integer.MAX_VALUE;
for (CityNode city: unsettledCities) {
int nodeDistance = distances.get(city);
if (nodeDistance < lowestDistance) {
lowestDistance = nodeDistance;
lowestDistanceCity = city;
}
}
return lowestDistanceCity;
}
Edit: an implementation using adjacency matrix could look like this:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class DijkstraAdjacencyMatrix {
public static void main(String[] args) {
Set<CityNode> cities = new HashSet<>();
CityNode a = new CityNode("A");
CityNode b = new CityNode("B");
CityNode c = new CityNode("C");
CityNode d = new CityNode("D");
CityNode e = new CityNode("E");
cities.addAll(List.of(a,b,c,d,e));
CitiesGraph graph = new CitiesGraph(cities);
graph.connectCities(a, b, 50);
graph.connectCities(b, c, 30);
graph.connectCities(c, d, 40);
graph.connectCities(d, e, 20);
graph.show();
FindPath findPath = new FindPath();
System.out.println(findPath.calculateShortestPath(graph, a, e)); //prints 140 as expected
//to add some complexity we need to construct a new CitiesGraph. It is not reusable
CityNode f = new CityNode("F");
cities.add(f);
graph = new CitiesGraph(cities);
graph.connectCities(a, b, 50);
graph.connectCities(b, c, 30);
graph.connectCities(c, d, 40);
graph.connectCities(d, e, 20);
graph.connectCities(b, f, 10);
graph.connectCities(f, d, 10);
graph.show();
System.out.println(findPath.calculateShortestPath(graph, a, e));//prints 90 as expected
}
}
class FindPath{
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
Map<CityNode, Integer> distances;
//using Dijkstra algorithm
public int calculateShortestPath(CitiesGraph graph, CityNode from, CityNode to) {
//a container to hold which cities the algorithm has visited
Set<CityNode> settledCities = new HashSet<>();
//a container to hold which cities the algorithm has to visit
Set<CityNode> unsettledCities = new HashSet<>();
unsettledCities.add(from);
//map to hold distances of all node from origin. at the end this map should contain
//the shortest distance between origin (from) to all other nodes
distances = new HashMap<>();
//initialize map with values: 0 distance to origin, infinite distance to all others
//infinite means no connection between nodes
for(CityNode city :graph.getCities()){
int distance = city.equals(from) ? 0 : Integer.MAX_VALUE;
distances.put(city, distance);
}
while (unsettledCities.size() != 0) {
//get the unvisited city with the lowest distance
CityNode currentCity = getLowestDistanceCity(unsettledCities);
//remove from unvisited, add to visited
unsettledCities.remove(currentCity); settledCities.add(currentCity);
Collection<CityNode> connectedCities = graph.getCitiesConnectedTo(currentCity);
//iterate over connected city to update distance to each
for( CityNode city : connectedCities){
//check if new distance is shorted than the previously found distance
int distanceToCity = graph.getDistanceBetween(city, currentCity);
if(distanceToCity <= 0) {
continue;
}
if(distances.get(currentCity) + distanceToCity < distances.get(city)){
//if so, keep the shortest distance found
distances.put(city,distances.get(currentCity) + distanceToCity);
//if city has not been visited yet, add it to unsettledCities
if(! settledCities.contains(city)) {
unsettledCities.add(city);
}
}
}
}
return distances.get(to);
}
private CityNode getLowestDistanceCity(Set <CityNode> unsettledCities) {
return unsettledCities.stream()
.min((c1,c2)-> Integer.compare(distances.get(c1), distances.get(c2)))
.orElse(null);
}
}
class CityNode {
private static int counter =0;
private final String name;
//assign unique id to each node. safer than to rely on unique name
private final int id = counter ++;
public CityNode(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder("City ");
sb.append(name).append(" (id=").append(id).append(")");
return sb.toString();
}
public int getId() {
return id;
}
#Override
public boolean equals(Object o) {
if(o == null || !(o instanceof CityNode)) return false;
CityNode c = (CityNode) o;
return c.getName().equalsIgnoreCase(name) && id == c.getId();
}
#Override
public int hashCode() {
int hash = 31 * 7 + id;
return name == null ? hash : name.hashCode();
}
}
class CitiesGraph{
//use set which prevents duplicate entries
private final Set<CityNode> cities;
private final int[][] adjacencyMatrix;
private static final int NOT_CONNECTED = -1;
public CitiesGraph(Set<CityNode> cities) {
this.cities = cities;
adjacencyMatrix = new int[cities.size()][cities.size()];
//initialize matrix
for(int row = 0; row < adjacencyMatrix.length ; row++){
for(int col = 0; col < adjacencyMatrix[row].length ; col++){
adjacencyMatrix[row][col] = row == col ? 0 : NOT_CONNECTED ;
}
}
}
public void connectCities(CityNode city1, CityNode city2, int distance) {
//assuming undirected graph
adjacencyMatrix[city1.getId()][city2.getId()] = distance;
adjacencyMatrix[city2.getId()][city1.getId()] = distance;
}
public int getDistanceBetween(CityNode city1, CityNode city2) {
return adjacencyMatrix[city1.getId()][city2.getId()];
}
public Collection<CityNode> getCitiesConnectedTo(CityNode city) {
Collection<CityNode> connectedCities = new ArrayList<>();
//iterate over row representing city's connections
int column = 0;
for(int distance : adjacencyMatrix[city.getId()]){
if(distance != NOT_CONNECTED && distance > 0) {
connectedCities.add(getCityById(column));
}
column++;
}
return connectedCities;
}
public CityNode getCityById(int id) {
for (CityNode city : cities) {
if (city.getId() == id) return city;
}
return null;
}
public void show() {
for(int[] row : adjacencyMatrix){
System.out.println(Arrays.toString(row));
}
}
//get a copy of cities list
public Collection<CityNode> getCities(){
return new ArrayList<>(cities);
}
}
I need help in adding Edge cost for my BFS algorithm. I don't have an idea how to add edge cost for the each vertex being added to the path. I will post code for your reference. Provide me some suggestions.
Graph.java
package algo;
import java.util.*;
public class Graph
{
private static Map<String, LinkedHashSet<HashMap<String, Double>>> map;
private ArrayList<String> nodes = new ArrayList<String>();
private static ArrayList<String> shortestPath = new ArrayList<String>();
public Graph()
{
}
public Graph(String[] nodes)
{
map = new HashMap<String,LinkedHashSet<HashMap<String, Double>>>();
for(int i=0;i<nodes.length;++i)
map.put(nodes[i], new LinkedHashSet<HashMap<String, Double>>());
}
public void addNeighbor(String node1,String node2, Double edgeCost)
{
LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node1);
HashMap<String, Double> innerMap = new HashMap<String, Double>();
if(map.get(node1)==null)
{
adjacent = new LinkedHashSet<HashMap<String, Double>>();
map.put(node1, adjacent);
}
innerMap.put(node2, edgeCost);
adjacent.add(innerMap);
}
public boolean memberOf(String node) {
return nodes.contains(node);
}
public LinkedList<HashMap<String, Double>> getNeighbours(String node) {
LinkedHashSet<HashMap<String, Double>> adjacent = map.get(node);
if(adjacent==null) {
return new LinkedList<HashMap<String, Double>>();
}
return new LinkedList<HashMap<String, Double>>(adjacent);
}
protected void storeNodes(String source, String destination)
{
if (!source.equals(destination))
{
if (!nodes.contains(destination))
{
nodes.add(destination);
}
}
if (!nodes.contains(source)) {
nodes.add(source);
}
}
public void getKeyValuePairs()
{
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext())
{
String key = iterator.next().toString();
LinkedHashSet<HashMap<String, Double>> value = map.get(key);
System.out.println(key + " " + value);
}
}
}
Main.java
package algo;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException
{
File file = new File("city.txt");
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
String [] tokens = line.split("\\s+");
String [] nodes = new String[tokens.length];
for (int i = 0; i < nodes.length; ++i) {
nodes[i] = tokens[i];
}
Graph g = new Graph(nodes);
String var_1 = tokens[0];
String var_2 = tokens[1];
Double var_3 = Double.parseDouble(tokens[2]);
g.addNeighbor(var_1, var_2,var_3);
while((line = br.readLine())!=null)
{
tokens = line.split("\\s+");
nodes = new String[tokens.length];
for (int i = 0; i < nodes.length; ++i) {
nodes[i] = tokens[i];
}
//Graph g = new Graph(nodes);
var_1 = tokens[0];
var_2 = tokens[1];
var_3 = Double.parseDouble(tokens[2]);
g.addNeighbor(var_1, var_2,var_3);
g.storeNodes(var_1, var_2);
}
g.getKeyValuePairs();
br.close();
}
}
city.txt
city1 city2 5.5
city1 city3 6
city2 city1 16
city2 city3 26
city2 city4 15.5
city2 city5 7
city3 city4 9
city3 city5 5
city4 city1 3.6
city4 city2 4
city5 city2 7.9
city5 city3 5
this is my bfs part of my code which i have tested without adding any edgecost
public static ArrayList<String> breadthFirstSearch(Graph graph,
String source,
String destination)
{
shortestPath.clear();
// A list that stores the path.
ArrayList<String> path = new ArrayList<String>();
// If the source is the same as destination, I'm done.
if (source.equals(destination) && graph.memberOf(source))
{
path.add(source);
return path;
}
// A queue to store the visited nodes.
ArrayDeque<String> queue = new ArrayDeque<String>();
// A queue to store the visited nodes.
ArrayDeque<String> visited = new ArrayDeque<String>();
queue.offer(source);
while (!queue.isEmpty()) {
String vertex = queue.poll();
visited.offer(vertex);
ArrayList<String> neighboursList = (ArrayList<String>) graph.getNeighbours(vertex);
int index = 0;
int neighboursSize = neighboursList.size();
while (index != neighboursSize) {
String neighbour = neighboursList.get(index);
path.add(neighbour);
path.add(vertex);
if (neighbour.equals(destination)) {
return processPath(source, destination, path);
} else {
if (!visited.contains(neighbour)) {
queue.offer(neighbour);
}
}
index++;
}
}
return null;
}
public static ArrayList<String> processPath(String src,
String destination,
ArrayList<String> path)
{
// Finds out where the destination node directly comes from.
int index = path.indexOf(destination);
String source = path.get(index + 1);
// Adds the destination node to the shortestPath.
shortestPath.add(0, destination);
if (source.equals(src)) {
// The original source node is found.
shortestPath.add(0, src);
return shortestPath;
} else {
// We find where the source node of the destination node
// comes from.
// We then set the source node to be the destination node.
return processPath(src, source, path);
}
}
my question is how do I add the edgecost to code in bfs part and provide the path cost from source to destination when executed.
To return the path and the cost you will need to create a class to hold both values:
class CostedPath {
private final List<String> path = new ArrayList<>();
private double cost = 0.0;
public CostedPath(String start) {
path.add(start);
}
public CostedPath addNode(String node, Graph graph) {
this.cost += graph.getCost(path.get(0), node);
path.add(0, node);
return this;
}
}
Your search should then return a CostedPath from processPath.
private CostedPath processPath(String start, String end, List<String> path, Graph graph) {
{
String previous = path.get(path.indexOf(end) + 1);
if (previous.equals(start))
return new CostedPath(start);
else
return processPath(start, previous, path, graph).addNode(end, graph);
}
Your code would be a lot more readable if you split your classes up more.
class Vertex {
private final String name;
private final Set<Edge> edges;
}
class Edge {
private final Vertex end;
private final double cost;
}
class Graph {
private final Set<Vertex> vertices;
}
class Path {
private final Vertex start;
private final List<Edge> edges;
}
Once you've done that you'll find that it's a lot more obvious where to add logic that's related to a particular class and the data you need will be available when you need it. For example, it's now trivial to convert a Path to a total cost:
public double getCost() {
return edges.stream().mapToDouble(Edge::getCost).sum();
}
This is much cleaner code than having to pass the original graph around to find the cost of an edge.
I have an object and client class created which prints coordinates in order of their distance from the origin. The client class asks the user how many dimensions they want the array to have (x,y or x,y,z) how many points they want generated, and a range from which each coordinate will run from (ex. -x to x, -y to y etc.). When I run the program it prints out the correct number of points, but there is always one extra element in the array (etc. when user enters dimension of array as '4', it always prints out one extra element -> [4, 5, 9, 6, 1]). Why is this happening?
Client Class
import java.io.*;
public class MA {
public MA() { }
public static void main(String args[]) throws IOException {
String myString = "arrayNumPoints.txt";
int numpoints = 0;
int dimension = 0;
double lengthscale = 0;
double [][] points = new double[numpoints][dimension + 1];
BufferedReader myInput = new BufferedReader(new InputStreamReader(System.in));
MB pointsB = new MB();
System.out.println("Enter number of points:");
String numpointsA = myInput.readLine();
numpoints = Integer.parseInt(numpointsA);
pointsB.setnumpoints(numpoints);
System.out.println("Enter the dimension:");
String dimensionA = myInput.readLine();
dimension = Integer.parseInt(dimensionA);
pointsB.setdim(dimension);
System.out.println("Enter length(range):");
String lengthscaleA = myInput.readLine();
lengthscale = Double.parseDouble(lengthscaleA);
pointsB.setlengthscale(lengthscale);
pointsB = new MB(numpoints, lengthscale, dimension, points);
pointsB.fillarray(pointsB.getarray(), pointsB.getlengthscale(), pointsB.getdim(), pointsB.getnumpoints());
pointsB.caldistance(pointsB.getarray(), pointsB.getnumpoints(), pointsB.getdim());
pointsB.sort(pointsB.getarray(), 0, pointsB.getnumpoints()-1, pointsB.getdim());
pointsB.writefile(pointsB.getarray(), pointsB.getnumpoints(), myString);
pointsB.readfile(myString);
}
}
Object Class
import java.io.*;
import java.util.Arrays;
public class MB {
//variables and arrays are declared
private double lengthscale;
private int numpoints;
private int dimension;
private double [][] points;
//constructor
public MB() { }
//constructor
public MB(double [][] points) {
numpoints = 0;
lengthscale = 0;
dimension = 0;
points = new double[numpoints][dimension + 1];
}
//constructor
public MB(int mynumpoints, double mylengthscale, int mydimension, double [][] mypoints) {
numpoints = mynumpoints;
lengthscale = mylengthscale;
dimension = mydimension;
points = new double[numpoints][dimension + 1];
}
//numpoints getter
public int getnumpoints()
{
return numpoints;
}
//numpoints setter
public void setnumpoints(int mynumpoints) {
numpoints = mynumpoints;
}
//lengthscale getter
public double getlengthscale() {
return lengthscale;
}
//lengthscale setter
public void setlengthscale(double mylengthscale) {
lengthscale = mylengthscale;
}
//dimension getter
public int getdim() {
return dimension;
}
//dimension setter
public void setdim(int mydimension) {
dimension = mydimension;
}
//array getter
public double[][] getarray() {
return points;
}
//array setter
public void setarray(double [][]mypoints, int numpoints, int dimension) {
points[numpoints][dimension] = mypoints[numpoints][dimension];
}
//fill array method
public void fillarray(double [][]mypoints, double mylengthscale, int mydimension, int mynumpoints) throws IOException {
for(int x = 0; x < mynumpoints; x++)
{
for(int y = 0; y < mydimension; y++) {
//fills array with random points within the specified range
mypoints[x][y] = (dimension * Math.random() - 1) * mylengthscale;
}//end for
}//end for
}
//writefile method
public void writefile(double [][]mypoints, int mynumpoints, String myString) throws IOException {
//writes to myString
PrintWriter fileOut = new PrintWriter(new FileWriter(myString));
//for loop runs for length of mylengthscale
for(int m = 0; m < mynumpoints; m++) {
//prints points to file
fileOut.println(Arrays.toString(mypoints[m]));
}
//close file
fileOut.close();
//end for
}
//readfile metod
public void readfile(String myString) throws IOException
{
String filePath = myString;
//reads data from mString
BufferedReader in = new BufferedReader(new FileReader(new File(myString)));
String line = null;
while(( (line = in.readLine()) != null))
System.out.println(line);
in.close();
}
//caldistance method
public void caldistance(double [][]mypoints, int mynumpoints, int mydimension) {
//for loop; calculates distance for specified number of points
for(int i = 0; i < mynumpoints; i++) {
for(int k = 0; k < mydimension; k++) {
mypoints[i][mydimension] = mypoints[i][k] * mypoints[i][k];
}//end for loop
mypoints[i][mydimension] = Math.sqrt(mypoints[i][mydimension]);
}//end for loop
}
//sort method
public double[][] sort(double[][] mynewpoints, int down, int top, int mydimension) {
System.arraycopy(mynewpoints, 0, mynewpoints, 0, mynewpoints.length);
//variables are declared
int d = down;
int u = top;
//determines pivot point
double [] pivot = mynewpoints[(down + top)/2];
//sorts the values of the array, comparing it to the pivot
do {
while (mynewpoints[d][mydimension] < pivot[mydimension]) {
d++;
}
while (mynewpoints[u][mydimension] > pivot[mydimension]) {
u--;
}
if (d <= u) {
double[] temporary = new double[mynewpoints[d].length];
//compres values in array and switches them
for (int y = 0; y < mynewpoints[d].length; y++) {
temporary[y] = mynewpoints[d][y];
mynewpoints[d][y] = mynewpoints[u][y];
mynewpoints[u][y] = temporary[y];
}
d++;
u--;
}
} while (d <= u);
if (down < u) {
mynewpoints = sort(mynewpoints, mydimension, down, u);
}
if (d < top) {
mynewpoints = sort(mynewpoints, mydimension, d, top);
}
return mynewpoints;
}
}
You should be more specific (show us the code fragments, which you use and which go wrong).
However do you realize, that in your MB constructor :
//constructor
public MB(double [][] points) {
numpoints = 0;
lengthscale = 0;
dimension = 0;
points = new double[numpoints][dimension + 1];
}
The last line is not doing anything? You have to write it like this :
this.points = new double[numpoints][dimension + 1];
Because you have two variables points, one is class variable, second is passed as parameter. If this happens, without using this the non-class variable is chosen.
Probably because you're adding 1 to the dimension given by the user:
points = new double[numpoints][dimension + 1];
This results in the array having one more column than value of dimension.
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]);
}
}
}`}
I have been developing an implementation of the neighbourhood algorithm in Java for a physics project I am working on. I'm brand new to Java so I apologize for any idiocy that results.
I have been getting the error
''
incompatible types
found : void
required: java.util.List<VoronoiPoint>
'' on line 22 from the Java compiler in attempting to compile the program shown below. I cannot figure out why the variable ''thelist'' somehow turns into a void when I declared it to be of type List<VoronoiPoint>. If anybody can explain to me what is going on it would be much appreciated!
import java.lang.Double;
import java.util.*;
public class VoronoiTiling
{
public static void main(String args[])
{
Integer n = 10; //Number of dimensions of model parameter space
Integer ns = 20; //Number of points per iteration
Integer nr = 4; //Number of cells to populate
Integer iterations = 5; //Number of iterations
List<VoronoiPoint> thelist = VoronoiList.startlist(ns,n);
//System.out.println(thelist);
//System.out.println(thelist.get(1).misfit);
for (Integer i=0 ; i<thelist.size() ; i++)
{
thelist.get(i).setmisfit();
}
List<VoronoiPoint> orderedlist = Collections.sort(thelist);
Double distance = EuclidianDistance((thelist.get(1)).location,(thelist.get(2)).location);
System.out.println(distance);
}
public static Double EuclidianDistance(Double[] point1, Double[] point2)
{
Double distance=0.0;
for (int i = 0; i < point1.length; i++)
{
distance = distance + Math.pow((point1[i]-point2[i]),2);
}
return Math.sqrt(distance);
}
}
The other classes I used are here:
The VoronoiList class:
import java.util.*;
public class VoronoiList
{
public static List<VoronoiPoint> startlist(Integer ns, Integer n)
{
List<VoronoiPoint> thestartlist = new ArrayList<VoronoiPoint>();
for (int i = 0; i < ns; i++)
{
thestartlist.add(new VoronoiPoint(0.,n));
}
return thestartlist;
}
}
The VoronoiPoint class:
import java.util.Random;
public class VoronoiPoint implements Comparable<VoronoiPoint>
{
Double[] location;
private Random generator = new Random();
Double misfit = -1.;
//***************************************************************
public VoronoiPoint(Double misfit, Integer n)
{
location = new Double[n];
ParameterBoundaries boundaries = new ParameterBoundaries(n);
for(int i = 0; i < n; i++)
{
location[i] = boundaries.getboundaries(2*i)+2*generator.nextDouble();
}
}
//***************************************************************
//public Double[] getlocation()
//{
//return location;
//}
public void setlocationi(Integer i, Double j)
{
location[i] = j;
}
//***************************************************************
public void setmisfit()
{
Integer n = location.length;
Double tempmisfit = 0.0;
for(Integer i = 0; i < n; i++)
{
tempmisfit = tempmisfit + Math.pow((location[i]),2);
}
misfit = Math.sqrt(tempmisfit); // Temporarily just distance to centre
}
//public Double getmisfit()
//{
//return misfit;
//}
public int compareTo(VoronoiPoint b)
{
if (this.misfit<b.misfit) return -1;
else if (this.misfit==b.misfit) return 0;
return 1;
}
}
And the parameter boundaries class:
public class ParameterBoundaries
{
private Double[] boundaries; /*Set to 2n where n is dimensions of parameter space,
* it just makes it easier*/
public ParameterBoundaries(Integer n)
{
boundaries = new Double[2*n];
for(Integer i = 0; i<n; i++)
{
boundaries[2*i] = -1.0;
boundaries[2*i+1] = 1.0;
}
}
public Double getboundaries(Integer i)
{
return boundaries[i];
}
}
Collections.sort(..) sorts the original list. It doesn't return a new list. (Its return type is void)
Your code is wrong. Collections.sort() is an in-place sort function; it modifies the given list argument and returns nothing (void).