0

I'm trying to modify Dijkstra's algorithm to show all the paths that have the minimum value. So I decided to use a list of previous vertices. And I added an if clause that checks if the path is igual to the previous with minimum value I add the previous vertex as the parent of the current one. The problem is that I am getting a StackOverflow error and I don't know what is causing it. This is my code: The purpose of the code below is to calculate Dijkstra for all of the vertices in the graph, calculate the number of times a vertex appears in the minimum paths found and display in decrescent order the all of them.

public class Dijkstra {

    public static final Map<String, Integer> ordem = new HashMap<>();

    public static void main(String[] args) throws FileNotFoundException, IOException {
        List<Graph.Edge> edges = new ArrayList<>();

        try {
            FileReader arq = new FileReader("input.txt");
            BufferedReader fw = new BufferedReader(arq);
            String linha = "";
            while (fw.ready()) {
                linha = fw.readLine();
                if (!linha.equals("0,0,0")) {
                    String parts[] = linha.split(",");
                    ordem.put(parts[0], 0);
                    ordem.put(parts[1], 0);
                    Graph.Edge a = new Graph.Edge(parts[0], parts[1], 100 - Integer.parseInt(parts[2]));
                    edges.add(a);
                } else {
                    break;
                }

            }
            fw.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        Graph g = new Graph(edges);

        for (int i = 0; i < 5; i++) {
            g.dijkstra(String.valueOf(i));
            g.printAllPaths();
        }

        Object[] a = ordem.entrySet().toArray();
        Arrays.sort(a, new Comparator() {
            public int compare(Object o1, Object o2) {
                return ((Map.Entry<String, Integer>) o2).getValue()
                        .compareTo(((Map.Entry<String, Integer>) o1).getValue());
            }
        });
        for (Object e : a) {
            System.out.print(((Map.Entry<String, Integer>) e).getKey() + " ");
        }
        System.out.println("\n");
    }
}

class Graph {

    private final Map<String, Vertex> graph;

    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;
        }
    }

    public static class Vertex implements Comparable<Vertex> {

        public final String name;
        public int dist = Integer.MAX_VALUE; 
        public List<Vertex> previous = new ArrayList<>();
        public final Map<Vertex, Integer> neighbours = new HashMap<>();

        public Vertex(String name) {
            this.name = name;
        }

        private void printPath() {
            if (this == this.previous) {
            } else if (this.previous == null) {
            } else {
                //This is where I am getting the error
                for (int i = 0; i<this.previous.size(); i++){
                this.previous.get(i).printPath();
                Dijkstra.ordem.replace(this.name, Dijkstra.ordem.get(this.name) + 1);
            }

            }
        }

        public int compareTo(Vertex other) {
            if (dist == other.dist) {
                return name.compareTo(other.name);
            }

            return Integer.compare(dist, other.dist);
        }

        @Override
        public String toString() {
            return "(" + name + ", " + dist + ")";
        }
    }

    public Graph(List<Graph.Edge> edges) {
        graph = new HashMap<>(edges.size());

        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));
            }
        }

        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);
        }
    }


    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<>();

        // Inicializacao dos vertices
        for (Vertex v : graph.values()) {
            //v.previous = v == source ? list : null;
            if (v == source) {
                v.previous.add(source);
            } else {
                v.previous = new ArrayList<>();
            }
            v.dist = v == source ? 0 : Integer.MAX_VALUE;
            q.add(v);
        }

        dijkstra(q);
    }

    private void dijkstra(final NavigableSet<Vertex> q) {
        Vertex u, v;
        while (!q.isEmpty()) {

            u = q.pollFirst(); 
            if (u.dist == Integer.MAX_VALUE) {
            }
            for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) {
                v = a.getKey(); 

                final int alternateDist = u.dist + a.getValue();
                if (alternateDist < v.dist) {
                    q.remove(v);
                    v.dist = alternateDist;
                    v.previous.add(u);
                    q.add(v);
                } else if(alternateDist == v.dist) {
                    v.previous.add(u);
                }
            }
        }
    }


    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();
    }

    public void printAllPaths() {
        for (Vertex v : graph.values()) {
            v.printPath();
        }
    }
}

This is the error:

Exception in thread "main" java.lang.StackOverflowError
    at Graph$Vertex.printPath(Dijkstra.java:117)
    at Graph$Vertex.printPath(Dijkstra.java:118)
Marcos Guimaraes
  • 1,243
  • 4
  • 27
  • 50
  • Whoah, that's a lot of code. Do you really expect to have people trawl trough that? `StackOverflowException` usually happens when you have some unbounded recursion. Simply said: `void a() { a(); }`. – M. le Rutte Oct 16 '17 at 20:01
  • Do you also get it when you find paths in a small (say 3x3 or 4x4) grid? On that scale it may be possible to output every step and by doing so detect where your algorithm is wrong. – GolezTrol Oct 16 '17 at 20:04
  • Thanks for the reply! I just added a comment in the for loop where I am getting the error. @GolezTrol I am testing the code in a graph with 5 vertices and 5 edges. – Marcos Guimaraes Oct 16 '17 at 20:10
  • I haven't determined whether it's responsible for the issue you described, but your implementation is seriously flawed. Your `Vertex` class implements `Comparable` based on instances' `dist` members. You use this as the basis for recording them in a `TreeSet`, which, in turn, you attempt to use as a priority queue. You must not mutate elements of such a set in a way that could change their relative order, yet you do exactly that. At best, then, you cannot rely on reading elements out in the order you expect. – John Bollinger Oct 16 '17 at 21:06
  • Also, consider *not* adding the start vertex to its own list of predecessors. You seem to go out of your way to do it, and then you need special case code to handle it. Wouldn't just be easier, and more natural, to let the start vertex have an empty predecessor list? – John Bollinger Oct 16 '17 at 22:25

1 Answers1

0

As the Error message already suggests: Your dijkstra isn't the problem. The problem is printPath() calling itself.

Likely the culprit is

if (this == this.previous) {} ...

You compare Vertex this to List<Vertex> previous. Maybe you want to check

if (this == this.previous.get(this.previous.size() - 1)) {} ...

instead.

I didn't test this, because your code is (1.) too long and (2.) not self-contained (missing at least "input.txt").

AlexR
  • 2,412
  • 16
  • 26
  • Thanks for the reply! input.txt would be something like this: 0,1,70 1,2,50 2,3,88 3,4,20 4,2,5 0,0,0 Each line is an edge (first and second attributes are vertices and the third is the weight of the edge. Every edge must be in a different line of the file). I am going to try your suggestion. – Marcos Guimaraes Oct 16 '17 at 20:21