How to perform different basic traversals of graphs?

Tim Chaffin :

I am trying to perform an iterative breadth first traversal, iterative depth first traversal, and recursive depth first traversal of a given graph (using an adjacency matrix).

In its current state, my program outputs various wrong answers.

Here's some examples.

I am expecting

From Node A
DFS (iterative): A B H C D E I F G
DFS (recursive): A B H C D E I F G
BFS (iterative): A B D I H C E F G

but am instead getting

From Node A
DFS (iterative): A I D B H C F G E 
DFS (recursive): A B H C F D E I G 
BFS (iterative): A B D I H C E F G  

I'm unsure if the problem with my program lies within the implementation of the traversals, or my implementation of some other part of the program. To be more specific, I'm not sure if my implementation connectNode or getNeighbors method is what is causing the incorrect output, or if it is my implementation of the traversals.

EDIT: Neighbors are supposed to be chosen in ascending order, if that's important. Perhaps this is part of the problem?

EDIT2: I added the new line of code, thanks to @HylianPikachu's suggestion. I now get full answers, but they are still not in the correct order.

EDIT3: I added the code to make it so the root node is checked as visited for bfs and recursive dfs. I think. I should also note that I was given parts of this code and told to fill in the rest. The use of the stack and queue are what I was told to use, even though there might be better options.

EDIT4: Added what was suggested, and now, the Iterative BFS works and gets the correct result. However, both DSF searches still do not work. I modified the results of the program above, to show this.

import java.util.*;

public class GraphM {
    public Node rootNode;
    public List<Node> nodes = new ArrayList<Node>(); // nodes in graph
    public int[][] adjMatrix; // adjacency Matrix

    public void setRootNode(Node n) {
        rootNode = n;
    }

    public Node getRootNode() {
        return rootNode;
    }

    public void addNode(Node n) {
        nodes.add(n);
    }

    // This method connects two nodes
    public void connectNode(Node src, Node dst) {

        if(adjMatrix == null) {
            adjMatrix = new int[nodes.size()][nodes.size()];
        }

        adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
        adjMatrix[nodes.indexOf(dst)][nodes.indexOf(src)] = 1;

    }

    // Helper method to get one unvisited node from a given node n.
    private Node getUnvisitedChildNode(Node n) {
        int index = nodes.indexOf(n);
        int size = adjMatrix.length;
        for (int j = 0; j < size; j++)
            if (adjMatrix[index][j] == 1 && ((Node) nodes.get(j)).visited == false)
                return nodes.get(j);
        return null;
    }

    // get all neighboring nodes of node n.
    public List<Node> getNeighbors(Node n) {
        List<Node> neighbors = new ArrayList<Node>();

        for(int i = 0; i < nodes.size(); i ++) {
            if (adjMatrix[nodes.indexOf(n)][i] == 1) {
                neighbors.add(nodes.get(i));
            }
           Collections.sort(neighbors);
        }
        return neighbors;

    }

    // Helper methods for clearing visited property of node
    private void reset() {
        for (Node n : nodes)
            n.visited = false;
    }

    // Helper methods for printing the node label
    private void printNode(Node n) {
        System.out.print(n.label + " ");
    }

    // BFS traversal (iterative version)
    public void bfs() {


        Queue<Node> queue = new LinkedList<Node>();

        queue.add(rootNode);

        while(!queue.isEmpty()) {

            Node node = queue.poll();
            printNode(node);
            node.visited = true;

            List<Node> neighbors = getNeighbors(node); 

            for ( int i = 0; i < neighbors.size(); i ++) {
                Node n = neighbors.get(i);

                if (n != null && n.visited != true) {
                    queue.add(n);
                    n.visited = true;
                }
            }

        }

    }

    // DFS traversal (iterative version)
    public void dfs() {

        Stack<Node> stack = new Stack<Node>();
        stack.add(rootNode);
        while(!stack.isEmpty()){
            Node node = stack.pop();

            if(node.visited != true) {
                printNode(node);
                node.visited = true;
            }

            List<Node> neighbors = getNeighbors(node);
            for (int i = 0; i < neighbors.size(); i++) {
                Node n = neighbors.get(i);
                if(n != null && n.visited != true) {
                    stack.add(n);
                }
            }

        }

    }

    // DFS traversal (recursive version)
    public void dfs(Node n) {

        printNode(n);
        n.visited = true;
        List<Node> neighbors = getNeighbors(n);
        for (int i = 0; i < neighbors.size(); i ++) {
            Node node = neighbors.get(i);
            if(node != null && node.visited != true) {
                dfs(node);
            }
        }

    }

    // A simple Node class
    static class Node implements Comparable<Node> {
        public char label;
        public boolean visited = false;

        public Node(char label) {
            this.label = label;
        }

        public int compareTo(Node node) {
            return Character.compare(this.label,  node.label);
        }
    }


    // Test everything
    public static void main(String[] args) {

        Node n0 = new Node('A');
        Node n1 = new Node('B');
        Node n2 = new Node('C');
        Node n3 = new Node('D');
        Node n4 = new Node('E');
        Node n5 = new Node('F');
        Node n6 = new Node('G');
        Node n7 = new Node('H');
        Node n8 = new Node('I');

        // Create the graph (by adding nodes and edges between nodes)
        GraphM g = new GraphM();
        g.addNode(n0);
        g.addNode(n1);
        g.addNode(n2);
        g.addNode(n3);
        g.addNode(n4);
        g.addNode(n5);
        g.addNode(n6);
        g.addNode(n7);
        g.addNode(n8);

        g.connectNode(n0, n1);
        g.connectNode(n0, n3);
        g.connectNode(n0, n8);
        g.connectNode(n1, n7);
        g.connectNode(n2, n7);
        g.connectNode(n2, n3);
        g.connectNode(n3, n4);
        g.connectNode(n4, n8);
        g.connectNode(n5, n6);
        g.connectNode(n5, n2);

        // Perform the DFS and BFS traversal of the graph
        for (Node n : g.nodes) {
            g.setRootNode(n);

            System.out.print("From node ");
            g.printNode(n);

            System.out.print("\nDFS (iterative): ");
            g.dfs();
            g.reset();

            System.out.print("\nDFS (recursive): ");
            g.dfs(g.getRootNode());
            g.reset();

            System.out.print("\nBFS (iterative): ");
            g.bfs();
            g.reset();
            System.out.println("\n");
        }
    }
}
Hylian Pikachu :

So, we already covered the first part of your question, but I'll restate it here for those who follow. Whenever working with graphs and an adjacency matrix, probably the best way to initialize elements in the array is "both ways."

Instead of just using the following, which would require a specific vertex be listed first in order to find the neighbors:

adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;

Use this, which leads to searches that are agnostic of the vertex order:

adjMatrix[nodes.indexOf(src)][nodes.indexOf(dst)] = 1;
adjMatrix[nodes.indexOf(dst)][nodes.indexOf(src)] = 1;

Now, for ordering. You want the vertices to be outputted in order from "least" letter to "greatest" letter. We'll address each one of your data structures individually.

In BFS (iterative), you use a Queue. Queues are "first in, first out." In other words, the element that was least recently added to the Queue will be outputted first whenever you call queue.poll(). Thus, you need to add your nodes from least to greatest.

In DFS (iterative), you use a Stack. Stacks are "last in, first out." In other words, the element that was most recently added to the Stack will be outputted first whenever you call stack.pop(). Thus, you need to add your nodes from greatest to least.

In DFS (recursive), you use a List. Lists have no "in-out" ordering per se, as we can poll them in whatever order we want, but the easiest thing to do would just be to sort the List from least to greatest and output them in order.

With this in mind, we need to introduce protocol for sorting the graph. All three protocols use getNeighbors(), so we'll sort the outputted List immediately after we call that function. Lists can be ordered with the function Collections.sort(List l) from java.utils.Collections, but we first need to modify your nodes class so Java knows how to sort the Nodes. For further reading about the details of what I'm doing, you can look here, but this post is getting way longer than I intended already, so I'm going to just show the code here and let the interested explore the link themselves.

You would first tweak your Node class by implementing Comparable<Node> and adding the compareTo() function.

static class Node implements Comparable<Node>{
    public char label;
    public boolean visited = false;

    public Node(char label) {
        this.label = label;
    }

    @Override
    public int compareTo(Node that) {
       return Character.compare(this.label, that.label);
    }
}

Then, in the cases in which we want to order the List from least to greatest, we can use Collections.sort(neighbors). When we want it from greatest to least, we can use Collections.sort(neighbors, Collections.reverseOrder()). Our final code will look like this:

// BFS traversal (iterative version)
public void bfs() {


    Queue<Node> queue = new LinkedList<Node>();

    queue.add(rootNode);

    while(!queue.isEmpty()) {

        Node node = queue.poll();
        printNode(node);
        node.visited = true;

        List<Node> neighbors = getNeighbors(node); 
        //NEW CODE: Sort our neighbors List!
        Collections.sort(neighbors);

        for ( int i = 0; i < neighbors.size(); i ++) {
            Node n = neighbors.get(i);

            if (n != null && n.visited != true) {
                queue.add(n);
                n.visited = true;
            }
        }

    }

}

// DFS traversal (iterative version)
public void dfs() {

    Stack<Node> stack = new Stack<Node>();
    stack.add(rootNode);
    while(!stack.isEmpty()){
        Node node = stack.pop();

        if(node.visited != true) {
            printNode(node);
            node.visited = true;
        }

        List<Node> neighbors = getNeighbors(node);
        //NEW CODE: Sort our neighbors List in reverse order!
        Collections.sort(neighbors, Collections.reverseOrder());

        for (int i = 0; i < neighbors.size(); i++) {
            Node n = neighbors.get(i);
            if(n != null && n.visited != true) {
                stack.add(n);
            }
        }

    }

}

// DFS traversal (recursive version)
public void dfs(Node n) {

    printNode(n);
    n.visited = true;
    List<Node> neighbors = getNeighbors(n);
    //NEW CODE: Sort our neighbors List!
    Collections.sort(neighbors);

    for (int i = 0; i < neighbors.size(); i ++) {
        Node node = neighbors.get(i);
        if(node != null && node.visited != true) {
            dfs(node);
        }
    }

}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=394393&siteId=1