// Stephen Fulwider
//	A sample program to show working examples of Depth/Breadth First Search (DFS,BFS)

import java.util.LinkedList;
import java.util.Queue;

public class BFS
{
	public static void main(String[] args)
	{
		new BFS(); // I like doing things this way...
	}

	int N; // number of vertices in the graph
	boolean[][] G; // the graph as an adjacency matrix
				   // G[i][j] is true if there is an edge from i to j

	BFS()
	{
		setupGraph();
		System.out.println("------------------------------");
		System.out.println();

		// perform a BFS on the graph
		BFS();
		System.out.println();
		System.out.println("------------------------------");
		System.out.println();
		System.out.println("All done - have a good day!");
	}

	// initial setup of the graph
	void setupGraph()
	{
		// set up a graph with 8 vertices + 3 components that looks like:
		/*
			0 --- 1        5---6
			| \    \       |  /
			|  \    \      | /
			2   3----4     7
		*/
		N=8;
		G=new boolean[N][N];
		// notice that for each edge G[i][j] == G[j][i]
		// this means that the graph is undirected
		G[0][1]=G[1][0]=true; G[0][2]=G[2][0]=true; G[0][3]=G[3][0]=true;
		G[1][4]=G[4][1]=true; G[3][4]=G[4][3]=true; G[5][6]=G[6][5]=true;
		G[5][7]=G[7][5]=true; G[6][7]=G[7][6]=true;
	}

	// perform a BFS on the graph G
	void BFS()
	{
		// a visited array to mark which vertices have been visited in BFS
		boolean[] V=new boolean[N];

		int numComponets=0; // the number of components in the graph

		// do the BFS from each node not already visited
		for (int i=0; i<N; ++i)
			if (!V[i])
			{
				++numComponets;
				System.out.printf("BFS for component %d starting at node %d%n",numComponets,i);

				BFS(i,V);
			}
		System.out.println();
		System.out.printf("Finished BFS - found %d components.%n", numComponets);
	}

	// perform a BFS starting at node start
	void BFS(int start, boolean[] V)
	{
		Queue<Integer> Q=new LinkedList<Integer>(); // A queue to process nodes

		// start with only the start node in the queue and mark it as visited
		Q.offer(start);
		V[start]=true;

		// continue searching the graph while still nodes in the queue
		while (!Q.isEmpty())
		{
			int at=Q.poll(); // get the head of the queue
			System.out.printf("At node %d in the BFS%n",at);

			// add any unseen nodes to the queue to process, then mark them as
			// visited so they don't get re-added
			for (int i=0; i<N; ++i)
				if (G[at][i] && !V[i])
				{
					Q.offer(i);
					V[i]=true;
					System.out.printf("Adding node %d to the queue in the BFS%n", i);
				}
			System.out.printf("Done processing node %d%n", at);
		}
		System.out.printf("Finished with the BFS from start node %d%n", start);
	}
}
