Search code examples
javagraphnodesbreadth-first-search

How to list all paths from a node to another in a indirect graph?


I have a graph where its nodes are in the following structure:

Class Node:
   int source;
   int next;

So, I have the following nodes: [(1,2), (2,3), (3,4), (1,4)]

I wanted to list all possible paths from 1 to 3 it would list: [[(1,2),(2,3)],[(1,4),(4,3)].

I'm trying with this code, but I'm missing something:

public List<Node> getNodeNeighbors(Node n) {
    List<Node> filteredNodes = new ArrayList<Node>();
    List<Node> allNodes = (List<Node>) nodesRepository.findAll();
    for (Node node: allNodes) {
        if (node.source == n.next) {
            filteredNodes.add(node);
        }
    }
    return filteredNodes;
}

public List<Node> bfs(Node n, String destinationNodeNumber, List<Node> path) {
        visitedX.add(n); //visitedX is a global List to control visited nodes
        path.add(n); //local path to be listed
        List<Node> neighbors = getNodeNeighbors(n); //function to get node neighbors
        if (n.next.equals(destinationNodeNumber)) {
            allPaths.add(paths); //all paths to be listed
            path.remove(n);
        }
        for (Node nNode: neighbors) {
            if(!visitedX.contains(nNode)) {
                bfs(nNode, destinationNodeNumber, path);
            }
        }
        return null;
    }

Solution

  • There are many flaws in your code:

    • the name of your class Node is misleading: Edge would be a better name,
    • method getNodeNeighbors only considers one direction of each edge
    • what are the fields aCompany and anotherCompany? i assume you meant source and next?
    • what is class Contract?
    • destinationNodeNumber is a String; it should be an int.
    • the visitedX set prevents two paths from using a same edge; you just need to ensure that an edge doesn't appear more that once in a single path.
    • you actually implemented a DFS, not a BFS
    • you always add the same path to allPaths; you should make a copy instead.

    Here is a class Edge:

    public class Edge {
        final int source;
        final int next;
    
        Edge(int source, int next) {
            this.source = source;
            this.next = next;
        }
    
        @Override
        public String toString() {
            return "(" + source + "," + next + ')';
        }
    }
    

    Then the class Graph that contains the search algorithm:

    public class Graph {
        private final Iterable<Edge> allNodes;
    
        public Graph(Iterable<Edge> allNodes) {
            this.allNodes = allNodes;
        }
    
        public List<Edge> edgesFrom(int vertex) {
            List<Edge> filteredNodes = new ArrayList<Edge>();
            for (Edge node : allNodes) {
                if (node.source == vertex || node.next == vertex) {
                    filteredNodes.add(node);
                }
            }
            return filteredNodes;
        }
    
        public List<List<Edge>> allPaths(int source, int dest) {
            List<Edge> path = new ArrayList<>();
            List<List<Edge>> allPaths = new ArrayList<>();
            for (Edge n: edgesFrom(source)) {
                searchPaths(n, source, dest, path, allPaths);
            }            
            return allPaths;
        }
    
        private void searchPaths(Edge n, int source, int dest, List<Edge> path,
                List<List<Edge>> allPaths) {
            path.add(n); //local path to be listed
            int next = n.source == source ? n.next : n.source;
            List<Edge> neighbors = edgesFrom(next); //function to get node neighbors
            if (next == dest) {
                allPaths.add(new ArrayList<>(path)); //all paths to be listed
            }
            for (Edge nNode : neighbors) {
                if (!path.contains(nNode)) {
                    searchPaths(nNode, next, dest, path, allPaths);
                }
            }
            path.remove(n);
        }
    }
    

    And here is the example that uses these classes:

    Graph graph = new Graph(Arrays.asList(
            new Edge(1,2), new Edge(2,3), new Edge(3,4), new Edge(1,4)));
    List<List<Edge>> allPaths = graph.allPaths(1,3);
    for (List<Edge> path: allPaths) {
        System.out.println(path);
    }