# Breadth-First Search and Depth-First Search (2023)

## Motivation and Audience

This tutorial's motivation is to learn how Breadth-First Search (BFS) and Depth-First Search (DFS) in a theoretical level and apply it for path-planning and search algorithms practices. Readers of this tutorial assumes the reader has the following background and interests:

* Know how to code in MATLAB and understand coding logic
* Know basic concepts of data structures, mainly graph and trees
* This tutorial may also attract readers who are interested in implementing algorithms in their own projects

The rest of this tutorial is presented as follows:

Breath-First Search (BFS) is a searching algorithm for both graphs and trees following a first-in first-out (FIFO) approach and utilizes a queue.

In a graph, starting from an arbitrary node, the algorithm will explore the adjacent (or neighboring) nodes starting from the original. Each adjacent node is stored into a queue, to be explored later once the first node has been explored fully. For each item in the queue, once the algorithm starts to visit the neighboring nodes of the respective queued nodes, it will be marked as visited and dequeued (removed from queue) to avoid revisiting a node (cycles) again.

For a tree, it is very similar to a graph, but that process is called level order traversal. As you really can't have cycles in a tree, there is no need to have containers to watch out for visited leaves. The way this works is that starting from the root, it visits each leaf in a level then progress forward and will only continue until every leaf is visited in that respective level.

```           % Start and end nodes
startNode = [0, 2]; % [y,x]
endNodes = [6, 6];

% Grid dimensions
gridX = 6;
gridY = 6;

% Obstacles [y,x]
obstacles = [0, 3;
1, 1;
1, 2;
4, 3];

% Grid initializations
grid = zeros(gridX + 1, gridY + 1);

% Setting obstacles for grid
for i = 1:length(obstacles)
grid(obstacles(i, 1) + 1, obstacles(i, 2) + 1) = -1;
end

% BFS containers
queue = []; % queue container
visited = zeros(gridX + 1, gridY + 1); % visited container
pred = zeros(gridX + 1, gridY + 1, 2); % predecessor container

% Storing first node in queue and marking as visited
queue(end+1,:) = startNode + 1;
visited(startNode(1) + 1, startNode(2) + 1) = 0.1;

% BFS algorithm
pathFound = false;
while ~isempty(queue)
currNode = queue(1,:); % getting first node from queue
queue(1,:) = []; % remove from queue

% Check if endNode and currNode are the same
if isequal(currNode, endNodes + 1)
pathFound = true;
break;
end

adjNodes = [1, 0; -1, 0; 0, 1; 0, -1]; % up, down, left, right
for i = 1:4
% Check whether node is obstacle or visited
if newPos(1) >= 1 && newPos(1) <= gridX + 1 && newPos(2) >= 1 && newPos(2) <= gridY + 1 && ...
grid(newPos(1), newPos(2)) ~= -1 && visited(newPos(1), newPos(2)) == 0
%top line checks if within grid bounds, bottom checks if it is obstacles

queue(end+1,:) = newPos; % enqueue
visited(newPos(1), newPos(2)) = 1; % mark as visited
pred(newPos(1), newPos(2), :) = currNode; % store in predecessor container
end
end
end

% Backtrace to find final path
path = [];
if pathFound
currNode = endNodes + 1;
while ~isequal(currNode, startNode + 1)
path = [currNode - 1; path];
currNode = squeeze(pred(currNode(1), currNode(2), :))';
end
path = [startNode; path];
end

% Plotting final graph/path
if ~isempty(path)
plot(path(:, 2), path(:, 1), 'LineWidth', 2.0);
hold on;
end

% Plotting start and end nodes
plot(startNode(2) , startNode(1) , '-s', 'MarkerSize', 8, 'MarkerFaceColor', 'g');
text(startNode(2) + 0.25, startNode(1) + 0.25 , 'Start', 'FontSize', 10);

plot(endNodes(2) , endNodes(1), '-s', 'MarkerSize', 8, 'MarkerFaceColor', 'r');
text(endNodes(2) + 0.25, endNodes(1) + 0.25, 'End', 'FontSize', 10);

% Plotting obstacles
for i = 1:size(obstacles, 1)
plot(obstacles(i, 2), obstacles(i, 1), 'ks', 'MarkerSize', 10, 'MarkerFaceColor', 'k');
end

% Grid settings
grid on;
ax = gca;
ax.XColor = 'r';
ax.YColor = 'r';
ax.GridAlpha = 1;
axis equal;

xlabel('x [m]');
ylabel('y [m]');
title('BFS');

xlim([0 gridX]);
ylim([0 gridY]);

hold off;```

Depth-First Search (DFS) works similarity to BFS as they are both searching algorithms for both graphs and trees, but it follows a last-in first-out (LIFO) approach and a stack. There are two ways to do DFS, a recursive and iterative approach. The MATLAB code is iterative, but in the files, there will be both approaches in the Cpp folder.

In a graph, starting from an arbitrary node, the algorithm, instead of visiting every adjacent nodes, it will continue down a random path until it reaches the desired node, or a dead end. Once it reaches that dead end, it will backtrack to the previous node. It does this by storing all of the discovered nodes in a stack, using that a reference and then later removing that respective node if it has been backtracked. This can possibly lead to cycles, so, having a visiting container is used to avoid that possibility by ignoring it if that node has been visited before.

For a tree, DFS is unique because due to the property of continuing down a path, there are three types of traversal methods: Inorder, Preorder, and Postorder traversal. Inorder traversal starts at the bottom left most leaf and will traverse into the root of the subtree, then visting the right one. Preorder traversal starts at the root node, then travels into the left leaf first, then right leaf is followed. Postorder traversal starts at the bottom left most leaf, but this time, it travels to the right leaf of the subtree, then the root for it. For all of them, this process will continue until goal has been met. ```           % Start and end nodes
startNode = [0, 2]; % [y,x]
endNodes = [6, 6];

% Grid dimensions
gridX = 6;
gridY = 6;

% Obstacles [y,x]
obstacles = [0, 3;
1, 1;
1, 2;
4, 3];

% Grid initializations
grid = zeros(gridX + 1, gridY + 1);

% Setting obstacles for grid
for i = 1:length(obstacles)
grid(obstacles(i, 1) + 1, obstacles(i, 2) + 1) = -1;
end

% DFS containers
stack = []; % stack container
visited = zeros(gridX + 1, gridY + 1); % visited container
pred = zeros(gridX + 1, gridY + 1, 2); % predecessor container

% Storing first node in queue and marking as visited
queue(end+1,:) = startNode + 1;
visited(startNode(1) + 1, startNode(2) + 1) = 0.1;

% DFS algorithm (iterative)
pathFound = false;
while ~isempty(queue)
currNode = stack(end, :); % getting first node from stack
stack(end, :) = []; % remove from stack

% Check if endNode and currNode are the same
if isequal(currNode, endNodes + 1)
pathFound = true;
break;
end

adjNodes = [1, 0; -1, 0; 0, 1; 0, -1]; % up, down, left, right
for i = 1:4
% Check whether node is obstacle or visited
if newPos(1) >= 1 && newPos(1) <= gridX + 1 && newPos(2) >= 1 && newPos(2) <= gridY + 1 && ...
grid(newPos(1), newPos(2)) ~= -1 && visited(newPos(1), newPos(2)) == 0
%top line checks if within grid bounds, bottom checks if it is obstacles

stack(end + 1, :) = newPos; % store into the stack
visited(newPos(1), newPos(2)) = 1; % mark as visited
pred(newPos(1), newPos(2), :) = currNode; % store in predecessor in container
end
end
end

% Backtrace to find final path
path = [];
if pathFound
currNode = endNodes + 1;
while ~isequal(currNode, startNode + 1)
path = [currNode - 1; path];
currNode = squeeze(pred(currNode(1), currNode(2), :))';
end
path = [startNode; path];
end

% Plotting final graph/path
if ~isempty(path)
plot(path(:, 2), path(:, 1), 'LineWidth', 2.0);
hold on;
end

% Plotting start and end nodes
plot(startNode(2) , startNode(1) , '-s', 'MarkerSize', 8, 'MarkerFaceColor', 'g');
text(startNode(2) + 0.25, startNode(1) + 0.25 , 'Start', 'FontSize', 10);

plot(endNodes(2) , endNodes(1), '-s', 'MarkerSize', 8, 'MarkerFaceColor', 'r');
text(endNodes(2) + 0.25, endNodes(1) + 0.25, 'End', 'FontSize', 10);

% Plotting obstacles
for i = 1:size(obstacles, 1)
plot(obstacles(i, 2), obstacles(i, 1), 'ks', 'MarkerSize', 10, 'MarkerFaceColor', 'k');
end

% Grid settings
grid on;
ax = gca;
ax.XColor = 'r';
ax.YColor = 'r';
ax.GridAlpha = 1;
axis equal;

xlabel('x [m]');
ylabel('y [m]');
title('DFS');

xlim([0 gridX]);
ylim([0 gridY]);

hold off;```

### Practice

From the provided MATLAB Code, do the following:
Note: For all of them, you can choose what are the starting and end positions as long you follow the problems correctly and reasonably

Easy:
In either BFS or DFS, create an “obscured looking” path

Medium:
Change the bounds to an 5×5 grid and make DFS output the same path as BFS using the same amount of obstacles for both.

Hard:
Set a graph in which the same start position, end position, and obstacles are applied for both algorithms, but resulting paths deter because of one node (can change bounds to anything).

Possible Solutions

### Final Words

This tutorial's objective was to understand how the BFS and DFS algorithm work. Complete source code for this version of the algorithms can be found at the practice section of the tutorial. Once the concepts were conveyed the reader could try to implement BFS and DFS and other path planning algorithms into their own projects.

Speculating future work derived from this tutorial, includes learning and other algorithms such as Dijkstra and A* and apply it to robots and programs. In the big picture, the problem of understanding BFS and DFS can be solved with this tutorial.

For questions, clarifications, etc, Email: palusf1@unlv.nevada.edu 