Search code examples
c++matrixgraphnodesbreadth-first-search

How to write BFS function in C++?


#include <iostream>
#include <string>
#include <queue>

using namespace std;
void BFS(const string&, const string[], int[][10]);

int main()
{
    const int CAP = 10;

    string states[CAP] = { "Arizona", "California", "Idaho", "Nevada", "Oregon", "Utah", "Washington" };
    string Point;

    int matrix[CAP][CAP] =
    {
    {0,1,0,1,0,1,0},
    {1,0,0,1,1,0,0},
    {0,0,0,1,1,1,1},
    {0,1,1,1,0,0,1},
    {1,1,1,1,0,0,0},
    {0,0,1,0,1,0,0},
    {0,0,1,0,1,0,0}
    };


    BFS("California", states, matrix);


}

void BFS(const string& Point, const string states[], int matrix[][10])
{
    int SPoint = 0;
    queue<string> visited;
    queue<string> Queue;


    string temp = Point;

    visited.push(temp);
    do
    {

        for (int i = 0; i < 10; i++)
        {
            if (states[i] == temp)
            {
                SPoint = i;
            }
        }
        for (int i = 0; i < 10; i++)
        {
            if (matrix[SPoint][i] == 1)
            {
                Queue.push(states[i]);
            }
        }

        visited.push(Queue.front());
        Queue.pop();

        temp = visited.back();

    } while (!Queue.empty());


    for (int i = 0; i < 10; i++)
    {
        cout << visited.front();
        visited.pop();
    }


}

I'm doing an exercise where I have to make a function that does Breadth-First Search and prints out the visited path. But my function wouldn't print anything. What am I doing wrong here?

Note: The matrix is alphabetical order and represents the connection between states.

My expected output: California Arizona Oregon Nevada Utah Idaho Washington

Exercise description


Solution

  • While I won't offer a complete solution, I can help identify some of the issues the code exhibits.

    Major issues

    • Since you have a cyclic graph, it's important to mark nodes as visited during the BFS else you'll wind up with an infinite loop (which is why nothing gets printed in your current implementation). Your visited queue could be an unordered_set. When nodes are visited, add them to the set and write a conditional to avoid visiting them again.
    • The adjacency matrix doesn't appear correct. Since it's an undirected graph, I would anticipate that the matrix would be mirrored from top left to bottom right, but it's not. Also, there are no self-edges in the graph yet Nevada appears to have an edge to itself in the matrix.
    • There's no need to loop over the adjacency matrix--you can index into it by mapping digit indexes and string names appropriately. If you do need to loop, running to 10 is out of bounds on a 7x7 matrix.

    Minor issues

    • There's no sense in arbitrarily restricting the matrix size. Although the assignment enforces this, it's a poor design choice because the code needs to be rewritten any time you want to use a different input graph.
    • A matrix seems like a slightly awkward data structure here because it introduces an extra layer of indirection to translate strings into integers and back. Although the project doesn't permit it, I'd prefer using a structure like:

      std::unordered_map<std::string, std::vector<std::string>> graph({
          {"California", {"Oregon", "Nevada", "Arizona"}},
          // ... more states ...
      });
      

      Ideally, these would be Node objects with neighbor vector members instead of strings.

    • C++ offers std::vector and std::array which are preferable to C arrays. I assume they haven't been introduced yet in your class or aren't permitted on the assignment, but if you're stuck, you can try writing the code using them, then re-introducing your instructor's constraints after you get it working. If nothing else, it'd be a learning experience.
    • Avoid using namespace std;.
    • Reserve uppercase variable names for class names. Objects and primitives should be lowercase.

    Pseudocode for BFS

    This assumes the preferred data structure above; it's up to you to convert to and from strings and adjacency matrix indexes as needed.

    func BFS(string start, unordered_map<string, vector<string>> graph):
        vector traversal
        queue worklist = {start}
        unordered_set visited = {start}
    
        while !worklist.empty():
            curr = worklist.pop_front()            
            traversal.push_back(curr)
    
            for neighbor in graph[curr]:
                if neighbor not in visited:
                    visited.insert(neighbor)
                    worklist.push(neighbor)
    
        return traversal
    

    Since this is an assignment, I'll leave it at this and let you take another crack at the code. Good luck.