How to keep track of BFS depth in C++

2.2k views Asked by At

I want to do BFS on a 2D array, and each of the cell can be represented as pair<int,int>. I use queue<pair<int,int>> to keep track of cells at each level, but I find no clever way to keep track of the depth. (I don't want to define another struct to record the depth at each level)

How to keep track of depth in breadth first search? Here is a solution in Java. Each level is ended with null, and we increment the depth once we see null.

I am wondering if there's a similar elegant solution in C++. For now, I can think of the following ways:

1) count the number of cells(push()) at each level, and decrement the count after each pop(). Once count == 0, increase the depth.

2) use two queue and replace the old one with the new one at the end of each level. Increase the depth at the end of each iteration.

3) maybe stores a pointer to pair<int,int> in the queue and use NULL to separate levels?

2

There are 2 answers

1
Matt Timmermans On BEST ANSWER

(1) can work, but it's better/easier to set count=queue.size(), and decrement it each time you pop. When it gets to 0, increase the depth and set count=queue.size() again.

(2) works fine. Use std::swap to switch queues. This is what I usually do, because I like the outer for(int depth=0; !newnodes.empty(); ++depth) you can also use vectors instead of real queues, because you're not pushing and popping on the same object. The 2nd level loop is just an iteration through a vector.

(3) works, but it's quite wasteful. Other kinds of marker values can work, but I think the (1) above is better than this in all cases.

In cases where you prefer to use a std::deque instead of two vectors, I like to write it like this:

queue.push_back(root);
for (int depth=0; !queue.empty(); ++depth)
{
    for (size_t remaining=queue.size(); remaining>0; --remaining)
    {
        auto item = queue.pop_front();
        //.... queue.push_back(...), etc.
    }
}

... which is pretty much like my (1) above, but I get my nice depth loop and by writing the loop condition on remaining, we can avoid any other inner loop checks to queue.empty()

0
happydave On

A solution similar in spirit to inserting a null into the queue is to just insert a sentinel value that can't possibly occur as a cell. E.g. pair<numeric_limits<int>::max(), 0>