I have the following code modeling a lightweight framework for a vertex in my study of network diffusion. The initial prototype was from a framework in python, which I translated into Java. The issue I have is that while this code runs much faster than its python version up to 10000 vertices, for a larger number of vertices (100,000+), it grinds to a halt. In fact the python version executed in 1.2 minutes, while the java build didn't return even after 7 minutes of execution. I am not sure why the same code is breaking down at a larger number of vertices and I need help on fixing the code.
import java.util.*;
public class Vertex
{
private int id;
private HashMap<Integer, Double> connectedTo;
private int status;
public Vertex(int key)
{
this.id = key;
this.connectedTo = new HashMap<Integer, Double>();
this.status = 0;
}
public void addNeighbour(int nbr, double weight)
{
this.connectedTo.put(nbr, weight);
}
public int getId()
{
return this.id;
}
public double getWeight(int nbr)
{
return this.connectedTo.get(nbr);
}
public int getStatus()
{
return this.status;
}
public Set<Integer> getConnections()
{
return this.connectedTo.keySet();
}
//testing the class
public static void main(String[] args)
{
int noOfVertices = 100000;
Vertex[] vertexList = new Vertex[noOfVertices];
for (int i = 0; i < noOfVertices; i++) {
vertexList[i] = new Vertex(i);
}
for (Vertex v : vertexList) {
int degree = (int)(500*Math.random()); //random choice of degree
int neighbourCount = 0; // count number of neighbours built up
while (neighbourCount <= degree) {
int nbr = (int) (noOfVertices * Math.random()); // randomly choose a neighbour
double weight = Math.random(); // randomly assign a weight for the relationship
v.addNeighbour(nbr, weight);
neighbourCount++;
}
}
}
}
For reference, the python version of this code is as follows:
import random
class Vertex:
def __init__(self, key):
self.id = key
self.connectedTo = {}
def addNeighbor(self, nbr, weight=0):
self.connectedTo[nbr] = weight
def __str__(self):
return str(self.id) + ' connectedTo: ' \
+ str([x.id for x in self.connectedTo])
def getConnections(self):
return self.connectedTo.keys()
def getId(self):
return self.id
def getWeight(self, nbr):
return self.connectedTo[nbr]
if __name__ == '__main__':
numberOfVertices = 100000
vertexList = [Vertex(i) for i in range(numberOfVertices)] # list of vertices
for vertex in vertexList:
degree = 500*random.random()
# build up neighbors one by one
neighbourCount = 0
while neighbourCount <= degree:
neighbour = random.choice(range(numberOfVertices))
weight = random.random() # random choice of weight
vertex.addNeighbor(neighbour, weight)
neighbourCount = neighbourCount + 1
This was a very interesting problem, and I believe I learned something new as well. I tried optimizing the code in different ways, such as utilizing a parallel stream as well as using ThreadLocalRandom which can be up to three times faster than Random. However, I finally discovered the main bottleneck: allocated memory to the JVM.
Because you have so many elements being added to your Map (worst case is 500,000 with 100,000 vertices), you'll require a lot of memory (heap space). If you allow the JVM to dynamically allocate memory, then the program will take a very long time to execute. The way that I solved this was to pre-allocate memory to the JVM (specifically 3 GB) by applying -Xms3G as a VM Argument to the program's Run Configuration which can be done in your IDE or via the terminal.
I've also optimized your code a bit which I will post below (it completes in just a few seconds for me):
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
public class Test {
private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
public static void main(String[] args) {
int noOfVertices = 100_000;
Vertex[] vertexList = new Vertex[noOfVertices];
IntStream.range(0, noOfVertices).parallel().forEachOrdered(i -> {
vertexList[i] = new Vertex(i);
int degree = (int) (500 * RANDOM.nextDouble()); // random choice of degree
for (int j = 0; j <= degree; j++) {
int nbr = (int) (noOfVertices * RANDOM.nextDouble()); // randomly choose a neighbor
vertexList[i].addNeighbour(nbr, RANDOM.nextDouble());
}
});
}
}
class Vertex {
private int id;
private Map<Integer, Double> connectedTo;
private int status;
public Vertex(int id) {
this.id = id;
this.connectedTo = new HashMap<>(500);
}
public void addNeighbour(int nbr, double weight) {
this.connectedTo.put(nbr, weight);
}
public int getId() {
return this.id;
}
public double getWeight(int nbr) {
return this.connectedTo.get(nbr);
}
public int getStatus() {
return this.status;
}
public Set<Integer> getConnections() {
return this.connectedTo.keySet();
}
}
I'm not sure of the explicit consequences regarding using ThreadLocalRandom in a multithreaded environment, but you can switch it back to Math#random if you'd like.
Related
My code outputs this:
Computer 1 bets 5
Computer 2 bets 8
Computer 3 bets 4
Computer 4 bets 3
Computer 5 bets 8
I want to make a method "displayWinners()" that compares the bet value of all the objects in this array and returns all of the object id's with the highest bet value, in this case it would be Computer 2 and 5 with a bet of 8. How would i do that?
public class Computer {
Computer[] c;
private int id;
private int bet;
public void create(int numComps) {
int i;
c = new Computer[numComps];
for (i = 0; i < numComps; i++) {
c[i] = new Computer();
c[i].id = i+1;
c[i].bet = bet();
c[i].display();
}
displayWinners();
}
public int bet() {
return (int) (Math.random() * 10) + 1;
}
public void display() {
String name = "Computer " + id;
System.out.println(name + " bets " + bet);
}
public void displayWinners() {
System.out.println();
}
public static void main(String[] args) {
Computer c = new Computer();
c.create(5);
}
}
why don't you allocate a variable for an index of the maximum value and a value itself, and keep checking & rewriting the variable as function bet() is executed.
the code below is not properly verified but just have a look over.
public class Computer {
Computer[] c;
private int id;
private int bet;
private List<Integer> maxId;
private int maxBet;
public void create(int numComps) {
int i;
c = new Computer[numComps];
maxId = new ArrayList<Integer>();
maxBet = 0;
for (i = 0; i < numComps; i++) {
c[i] = new Computer();
c[i].id = i+1;
c[i].bet = bet();
c[i].display();
if(c[i].bet > maxBet) {
maxId = new ArrayList<Integer>();
maxId.add(c[i].id);
maxBet = c[i].bet;
}
else if(c[i].bet == maxBet) {
maxId.add(c[i].id);
}
}
displayWinners();
}
public int bet() {
return (int) (Math.random() * 10) + 1;
}
public void display() {
String name = "Computer " + id;
System.out.println(name + " bets " + bet);
}
public void displayWinners() {
System.out.format("Computer %d", maxId.get(0));
if(maxId.size() > 1) {
for(int i=1; i<maxId.size(); i++) {
System.out.format(" and %d", maxId.get(i));
}
}
System.out.format(" with a bet of %d\n", maxBet);
}
public static void main(String[] args) {
Computer c = new Computer();
c.create(5);
}
}
Ok, just for the fun to provide this with a small trick.
You just iterate your array.
Then, I will compare the current bet with the maximum value known using Integer.compare and base on the result, I will either:
r > 0 - clear the list and add the instance to the list
r == 0 - Add the instance to the list
r < 0 - Do nothing
Good to know, the actual value return by the method are simpler [-1, 0, 1], it will matter shortly.
Now, we can see some redondance in adding into the list, to reduce that, we are able to use a switch instead of ifs.
List<Computer> winners = new ArrayList<Computer>();
for ( Computer c : computers ){
int r = Integer.compare(c.getBet(), maxBet);
switch(r){
case 1: //Current bet is higher
maxIds.clear();
maxBet = c.getBet();
case 0: //Current bet is equals
winners.add(c);
case -1: //Current bet is lower (optional line, just for the explanation)
}
}
Since I don't use break, after we clear the list, we will add into it.
Note: A fail-safe should be added in case of Integer.compare implementation changes. The documentation state that it will return any value instead of -1, 0 or 1. But the current implementation is simpler :
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
First of all, I recommend you to split storage and business logic. Move all methods for show Computer class out.
So to find the winners you have to do following steps:
Create a list of computers (you can create an array or a list);
Iterate over the collection once to find the highest bet;
Iterate over the collection second time to filter out all computers with the highest bet.
If you ask such question, then I suppose, that no need of you right now to offer different sorting algorithms or special data structures (they all do the same, but much faster for big input data).
This is one of the possible solutions (I tried to keep it simple):
public class Foo {
public static void main(String[] args) throws IOException {
Computer[] computers = createComputer(5);
int highestBet = getHighestBet(computers);
List<Integer> ids = getIdsWithBet(computers, highestBet);
System.out.println(ids.stream().map(String::valueOf).collect(Collectors.joining(",")));
}
private static int getHighestBet(Computer... computers) {
int max = 0;
for (Computer computer : computers)
max = Math.max(max, computer.getBet());
return max;
}
private static List<Integer> getIdsWithBet(Computer[] computers, int bet) {
List<Integer> ids = new ArrayList<>(computers.length);
for (Computer computer : computers)
if (computer.getBet() == bet)
ids.add(computer.getId());
return ids;
}
// you van use List<Computer>
private static Computer[] createComputer(int total) {
Random random = new Random();
Computer[] computers = new Computer[total];
for (int i = 0; i < computers.length; i++) {
computers[i] = new Computer(i + 1, random.nextInt(10) + 1);
System.out.println(computers[i]);
}
return computers;
}
}
// It's better to use unmodifiable objects if you can
final class Computer {
private final int id;
private final int bet;
public Computer(int id, int bet) {
this.id = id;
this.bet = bet;
}
public int getId() {
return id;
}
public int getBet() {
return bet;
}
#Override
public String toString() {
return "Computer " + id + " bets " + bet;
}
}
import java.util.ArrayList at top of file
```
int maxBet = 0;
ArrayList<Integer> maxIds = new ArrayList<Integer>();
// This is a for each loop, it is saying, for each computer in the list of computers
for ( Computer computer : computers ){
/* if that computer has a higher bet than what we previously thought
was the highest, empty our list and set maxBet to that, and add this
computer to the list of computers that have that bet number */
if (computer.getBet() > maxBet){
maxIds.clear();
maxBet = computer.getBet();
maxIds.add(computer.getId());
// another computer has the same max bet value
} else if ( computer.getBet() == maxBet){
maxIds.add(computer.getId());
}
}
System.out.println("Max Bet: " + maxBet);
System.out.print("Computers with max bet: ");
// for each id in our list of computers that have the max bet
for ( int id : maxIds ){
System.out.print(id + " ");
}
I'm doing something that produces the right result. However, it is wrong from a design POV.
The point of the program is to list the result of all the powers of a number up to and including the user-defined limit.
I have a constructor which accepts the base and the exponent from the Scanner. Then a method, which utilises a for loop to calculate the power for each exponent.
Now, the problem is that I'm printing the result from each loop iteration directly from this method. This beats the point of private variables and it being void in the 1st place.
Therefore, I want to define a getter method which returns the result of each power to the output. I used to set them just fine for if/switch statements, but I don't know how to do the same for loops. If I assign the result to a variable within the loop and return that variable from the getter then it will return only the output from the final iteration.
Private implementation
package Chapter6Review;
public class Powers {
private int target;
private int power;
public Powers(int target, int power) {
this.target = target;
this.power = power;
}
public void calculatePower() {
for (int i = 0; i <= power; i++) {
System.out.println((int) Math.pow(target, i));
}
}
/*
public int getPower() {
return
}
*/
}
User interface
package Chapter6Review;
import java.util.Scanner;
public class PowersTester {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("Enter your base: ");
int target = in.nextInt();
System.out.print("Enter your exponent: ");
int power = in.nextInt();
Powers tester = new Powers(target, power);
tester.calculatePower();
}
}
You can simply use a List ;
public List<Integer> calculatePower() {
int p;
List<Integer> result = new ArrayList<Integer>();
for (int i = 0; i <= power; i++) {
p = (int) Math.pow(target, i);
result.add(p);
}
return result;
}
Then in you main method, you can iterate the list to print the powers like that :
List<Integer> result = new ArrayList<Integer>();
Powers tester = new Powers(target, power);
result = tester.calculatePower();
for (int i = 0; i < result.size(); i++) {
System.out.println(result.get(i));
}
You could store each of the results in a List:
List<Power> list = new ArrayList<>();
and when you call it add it as well
list.add(new Powers(target, power));
At the end you can iterate over the list like this:
for (Power power : list){
// your code
}
You might consider using streams as well
public List<Integer> calculatePower() {
return IntStream
.rangeClosed(0, power). // iterate from 0 till power inclusive
.mapToObj(i -> (int) Math.pow(target,i))
.collect(Collectors.toList()); // get result as list
}
Thanks for all the answers. Using a list seems to be a good choice.
Since I haven't covered lists yet, I resorted to this solution for now. But I don't like having code that can affect the solution in the main. Ideally, the loop should go in the private implementation.
Main
Powers tester = new Powers(target, power);
for (int i = 0; i <= power; i++) {
tester.calculatePower(i);
System.out.println(tester.getPower());
}
Private implementation
public void calculatePower(int iPower) {
result = (int) Math.pow(target, iPower);
}
public int getPower() {
return result;
}
So i am trying to build a genetic algorithm on java i stuck on getting
fitness of my population here 3 classes from my project:
Class Individu
public class Individu {
int Popsize=4;
int Health[]= new int[Popsize];
int Attack[]= new int[Popsize];
int Atspeed[]= new int[Popsize];
int Move[]= new int[Popsize];
int health,attack,lifetime,dmgdone,attspeed,range,move;
double fitness;
double Pitness[]= new double[20];
Random random = new Random();
public int setHealth(){
health = random.nextInt(150 - 75) + 75;
return health;
}
public int setAttack(){
attack = random.nextInt(10 - 5) + 10;
return attack;
}
public int setAttspeed(){
attspeed = random.nextInt(3 - 1) + 3;
return attspeed;
}
public int setMoveSpeed(){
move = random.nextInt(8 - 4) + 1;
return move;
}
public int getGeneHealth(int index) {
return Health[index];
}
public int getGeneAttack(int index) {
return Attack[index];
}
public int getGeneAtspedd(int index) {
return Atspeed[index];
}
public int getGeneMove(int index) {
return Move[index];
}
public void setGene(int index, int value) {
Health[index]=value;
Attack[index]=value;
Atspeed[index]=value;
Move[index]=value;
fitness = 0;
}
public int size() {
return Popsize;
}
public double[] GenerateIndividual(){
for (int i = 0; i <Popsize; i++) {
Health[i]=setHealth();
Attack[i]=setAttack();
Atspeed[i]=setAttspeed();
Move[i]=setMoveSpeed();
}
return Pitness;
}
Class Fitness
public class Fitness {
Individu individu= new Individu();
double fitness;
double Pitness[]= new double[20];
public double getFitness(){
individu.GenerateIndividual();
for (int i = 0; i <=3; i++) {
fitness=
individu.getGeneHealth(i)+individu.getGeneAtspedd(i)+
individu.getGeneAttack(i)+
individu.getGeneMove(i));
fitness=fitness/171;
Pitness[i]=fitness;
System.out.println("Health from class
fitness"+individu.Health[i]);
}
return fitness;
}
}
Main Class
public class main {
public static void main(String[] args) {
Individu aaa=new Individu();
Fitness bbb= new Fitness();
bbb.getFitness();
aaa.GenerateIndividual();
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(3);
for (int i=0; i<=3; i++){
//System.out.println("Fitness ");
System.out.println("Generasi ke :"+i+1);
System.out.println("Health "+aaa.getGeneHealth(i));
System.out.println("Attackspeed "+aaa.getGeneAtspedd(i));
System.out.println("Attack "+aaa.getGeneAttack(i));
System.out.println("movementSpeed "+aaa.getGeneMove(i));
}
}
}
What i struggle is when i run this script i got 2 double value from 1 variable first value is from Fitness class as i printed here
System.out.println("Health from class fitness"+individu.Health[i]);
and second variable i printed here from Main Class
System.out.println("Health "+aaa.getGeneHealth(i));
that 2 variable is always have different value causing my fitness and my generation is not correlated each other.
My question is how to make this 2 variable print same value?
Well, aside from the many problems I can detect about the essentials of Genetic Algorithms, I see 'individu' and 'aaa' are two different Java objects.
Individu aaa=new Individu();
aaa.GenerateIndividual();
and
Individu individu= new Individu();
individu.GenerateIndividual();
Since your Health and Fitness are randomly generated on GenerateIndividual(), both 'aaa' and 'individu' will get different Health values.
I strongly recommend you to review GA essentials, since I can see many conception errors in your system.
I am practicing some Java and one of the applications I am writing asks to output the world population in the next 75 years.
I am using the population growth model. My issue is that my application outputs 'Infinity' in the column where the estimated population should be output.
This is my code:
import java.util.Calendar;
import java.util.regex.Matcher;
public class WorldPopulationGrowth {
public static void main(String[] args) {
double currentWorldPopulation = 7.4e9;
double worldPopulationGrowthRate = 1.13;
double anticipatedWorldPopulation;
int initialYear = Calendar.getInstance().get(Calendar.YEAR);
System.out.println("Year\tAnticipated World Population (in billions)\tPopulation " +
"increase since last year");
System.out.println(String.format("%d\t%.1e\t\t\t\t\t\t\t\t\t\t\tNA", initialYear, currentWorldPopulation) );
for(int i=1; i < 76; i++){
int year = initialYear + i;
double growthExponential = worldPopulationGrowthRate*year*1.0;
anticipatedWorldPopulation = currentWorldPopulation * Math.pow(Math.E, growthExponential);
System.out.println(String.format("%d\t%.1e\t\t\t\t\t\t\t\t\t\t\t", year, anticipatedWorldPopulation));
currentWorldPopulation = anticipatedWorldPopulation;
}
}
}
Let's take a careful look at the first iteration of your code, as if we were debugging it (Make sure you try to do this in the future!)
currentWorldPopulation = 7.4e9
worldPopulationGrowthRate is 1.13
initialYear is 2016
your loop begins, i is 1
year is set to 2017
growthExponential is set to 1.13 * 2017 = 2279.21 (this is the start of your problem)
anticipatedWorldPopulation is set to 7.4e9 * e^2279.21
this is roughly 7.4e9 * 7.05e989... KABOOM
Revisit your calculations, and step through your application (ideally in a debugger) to see your problems.
#Krease found your problem.
I recoded it. Once you fix the issue he found it's fine. I used JDK 8 lambdas and gave you both percentage and exponential growth models. The code prints both for comparison:
import java.util.function.DoubleFunction;
/**
* Simplistic population growth model
* #link https://stackoverflow.com/questions/38805318/getting-infinity-output-instead-of-actual-numbers/38805409?noredirect=1#comment64979614_38805409
*/
public class WorldPopulationGrowth {
public static void main(String[] args) {
double currentWorldPopulation = 7.4e9;
double worldPopulationGrowthRate = 1.13;
int numYears = 76;
int startYear = 1976;
double populationExponential = currentWorldPopulation;
ExponentialGrowthModel modelExpGrowth = new ExponentialGrowthModel(worldPopulationGrowthRate);
double populationPercentage = currentWorldPopulation;
PercentageGrowthModel modelPercentGrowth = new PercentageGrowthModel(worldPopulationGrowthRate);
System.out.println(String.format("%10s %20.3e %20.3e", startYear, currentWorldPopulation, currentWorldPopulation));
for (int i = 1; i < numYears; ++i) {
populationExponential = modelExpGrowth.apply(populationExponential);
populationPercentage = modelPercentGrowth.apply(populationPercentage);
System.out.println(String.format("%10s %20.3e %20.3e", startYear+i, populationExponential, populationPercentage));
}
}
}
class ExponentialGrowthModel implements DoubleFunction<Double> {
private double exponent;
ExponentialGrowthModel(double exponent) {
this.exponent = exponent;
}
private double getExponent() {
return exponent;
}
public void setExponent(double exponent) {
this.exponent = exponent;
}
#Override
public Double apply(double value) {
return value*Math.exp(this.getExponent());
}
}
class PercentageGrowthModel implements DoubleFunction<Double> {
private double percentageIncrease;
PercentageGrowthModel(double percentageIncrease) {
this.percentageIncrease = percentageIncrease;
}
private double getPercentageIncrease() {
return percentageIncrease;
}
public void setPercentageIncrease(double percentageIncrease) {
this.percentageIncrease = percentageIncrease;
}
#Override
public Double apply(double value) {
return value*(this.getPercentageIncrease());
}
}
I have a DFS visit recursive method that sometimes throws a StackOverflowError. Since the size of the graph is large (around 20000 vertices), recursive calls are many, and so I tried to run with -Xss10M and everything works.
I'd just like to understand why adding at the beginning of the method a System.out.println, even without -Xss10M, the method doesn't throw any StackOverflowError. How is it possible?
This is the DFS visit method:
private int dfsVisit(Vertex<T> v, int time){
// System.out.println("Hello");
Vertex<T> n;
time++;
v.d = time;
v.color = Vertex.Color.GRAY;
for (Map.Entry<Vertex<T>, Float> a : v.neighbours.entrySet()){
n = a.getKey();
if(n.color == Vertex.Color.WHITE){
n.previous = v;
time = dfsVisit(n, time);
}
}
v.color = Vertex.Color.BLACK;
time++;
v.f = time;
return time;
}
This is the complete code
import java.io.*;
import java.util.*;
class Graph<T> {
private final Map<T, Vertex<T>> graph;
public static class Edge<T>{
public final T v1, v2;
public final float dist;
public Edge(T v1, T v2, float dist) {
this.v1 = v1;
this.v2 = v2;
this.dist = dist;
}
}
public static class Vertex<T> implements Comparable<Vertex>{ // SPOSTARE VAR IST NEL COSTRUTTORE
public enum Color {WHITE, GRAY, BLACK, UNKNOWN};
public final T name;
public float dist;
public Vertex<T> previous;
public final Map<Vertex<T>, Float> neighbours;
public Color color;
public int d, f;
public Vertex(T name) {
this.name = name;
dist = Float.MAX_VALUE;
previous = null;
neighbours = new HashMap<Vertex<T>, Float>(); // adjacency list
color = Color.UNKNOWN;
d = 0;
f = 0;
}
private void printPath() {
if (this == this.previous) {
System.out.print(this.name);
} else if (this.previous == null) {
System.out.print(this.name + " unreached");
} else {
this.previous.printPath();
System.out.print(" -> " + this.name + "(" + this.dist + ")");
}
}
public int compareTo(Vertex other){
if(this.dist == other.dist)
return 0;
else if(this.dist > other.dist)
return 1;
else
return -1;
}
}
// Builds a graph from an array of edges
public Graph(ArrayList<Graph.Edge> edges) {
graph = new HashMap<>(edges.size());
// add vertices
for (Edge<T> 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));
}
// create adjacency list
for (Edge<T> 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);
}
}
public void dijkstra(T startName) {
if (!graph.containsKey(startName)) {
System.err.println("Graph doesn't contain start vertex " + startName);
return;
}
final Vertex<T> source = graph.get(startName);
NavigableSet<Vertex<T>> q = new TreeSet<>(); // priority queue
// set-up vertices
for (Vertex<T> v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Float.MAX_VALUE;
q.add(v);
}
dijkstra(q);
}
private void dijkstra(final NavigableSet<Vertex<T>> q) {
Vertex<T> u, v;
while (!q.isEmpty()) {
u = q.pollFirst();
if (u.dist == Float.MAX_VALUE) break; //???????????
for (Map.Entry<Vertex<T>, Float> a : u.neighbours.entrySet()) {
v = a.getKey();
final float alternateDist = u.dist + a.getValue();
if (alternateDist < v.dist) {
q.remove(v);
v.dist = alternateDist;
v.previous = u;
q.add(v);
}
}
}
}
public void printPath(T endName) {
if (!graph.containsKey(endName)) {
System.err.println("Graph doesn't contain end vertex " + "\"" + endName + "\"" );
return;
}
graph.get(endName).printPath();
System.out.println();
}
public void printAllPaths() {
for (Vertex<T> v : graph.values()) {
v.printPath();
System.out.println();
}
}
public Vertex<T> getVertex(T key){
if(graph.containsKey(key))
return graph.get(key);
return null;
}
public void printAdjacencyList(){
System.out.println("Adjacency list:");
for(Vertex<T> v : graph.values()){
System.out.print(v.name + ":\t");
for (Map.Entry<Vertex<T>, Float> a : v.neighbours.entrySet()){
System.out.print(a.getKey().name + "(" + a.getValue() + ") | ");
}
System.out.println();
}
}
/*
P.S. I know that if only used to calculate the connected components of the graph, dfs visit
could be written differently but I preferred to write it in a more general way, so that it
can be reused if necessary.
*/
private int dfsVisit(Vertex<T> v, int time){
// System.out.println("ciao");
Vertex<T> n;
time++;
v.d = time;
v.color = Vertex.Color.GRAY;
for (Map.Entry<Vertex<T>, Float> a : v.neighbours.entrySet()){
n = a.getKey();
if(n.color == Vertex.Color.WHITE){
n.previous = v;
time = dfsVisit(n, time);
}
}
v.color = Vertex.Color.BLACK;
time++;
v.f = time;
return time;
}
/*
Print the size of the connected components of the graph
*/
public void connectedComponents(){
for(Vertex<T> v : graph.values()){
v.color = Vertex.Color.WHITE;
v.previous = null;
}
for(Vertex<T> v : graph.values()){
if(v.color == Vertex.Color.WHITE)
System.out.println(dfsVisit(v, 0)/2);
}
}
}
here's the test class
import java.io.*;
import java.util.*;
public class Dijkstra {
private static ArrayList<Graph.Edge> a = new ArrayList<Graph.Edge>();
private static final String START = "torino";
private static final String END = "catania";
public static void main(String[] args) {
String fileName = "italian_dist_graph.txt";
try{
Scanner inputStream = new Scanner(new File(fileName));
String record;
while(inputStream.hasNextLine()){
record = inputStream.nextLine();
String[] array = record.split(",");
String from = array[0];
String to = array[1];
float dist = Float.parseFloat(array[2]);
a.add(new Graph.Edge(from, to, dist));
}
inputStream.close();
} catch(FileNotFoundException e){
System.out.println("Impossibile trovare il file "+fileName);
}
Graph<String> g = new Graph<String>(a);
g.dijkstra(START);
g.printPath(END);
//System.out.printf("%f\n", g.getVertex(END).dist/1000.0f);
g.connectedComponents();
}
}
N.B. try to comment g.dijkstra(START) and g.printPath(END); everything seems to work.
Here's the link to the data set
https://drive.google.com/open?id=0B7XZY8cd0L_fZVl1aERlRmhQN0k
Some general recommendations:
Your code mixes up attributes of vertices, that are related to a single run of dfs and such that are direct attributes of the vertices. Bad bad bad style. This is quite likely to break any more complex algorithm, can produce unexpected behavior and would require clearing the states after each run, to ensure stability of the code. Instead keep states that are related to a single run of a algorithm only visible to that function. E.g. store the states inside a Map, use the decorator-pattern to create a datastructure that provides additional attributes and that has method-local scope, etc.. As an example: running your code twice on the same graph (same Object) with the same input without clearing all states will lead to a wrong result (1).
In addition: creating an iterative version of DFS isn't exactly hard, so you should give it a try, especially since your graph appears to be pretty large.
As for why your code works (or doesn't) the way it does:
This is hard to tell, since it depends upon quite a lot of factors. You didn't provide full code, so I can't rerun any tests, or verify that everything behaves the way it should. The most likely answers:
Vertex uses the default hash-code provided by Object. This leads to random ordering of the entries in the map of neighbours, thus the order in which specific paths are traversed is random in each run and most likely different. Thus you're traversing the graph using random paths, that quite likely (especially due to the size of your graph) differ for each run. The reason isn't the System.out.println, but the mere fact, that your code generates a different structure (from a ordering-POV, not mathematical), each time it runs plus the coincident, that for some pretty weird reason each build of the graph, that doesn't reach the necessary recursion-depth for a StackOverflow, and the code compiled with System.out.println appeared together.
The Java compiler, or JIT modifies the behavior of the code in a weird way. Modern compilers have the tendency to produce quite weird code in their attempts to optimize everything they can get hold off.