Breadth-First Search in python

Gennadiy Shevtsov
4 min readMar 17, 2023

Breadth-First Search (BFS) is an algorithm used to traverse and search a graph or tree data structure. It starts at a specified root node and explores all the neighboring nodes at the current depth level before moving on to the next level. In this article, we will explore how to implement BFS in Python.

Overview of Breadth-First Search Algorithm

BFS is a popular algorithm used in many applications such as graph traversal, shortest path finding, web crawlers, and many more. It traverses a graph in a level-by-level order, starting at the root node and exploring all the neighboring nodes at the same level before moving on to the next level.

BFS uses a queue data structure to store the nodes that need to be explored. It starts with the root node and enqueues it into the queue. It then dequeues the next node in the queue and enqueues all of its neighbors. This process continues until all nodes have been explored.

BFS Algorithm Steps:

Enqueue the starting node into the queue.
While the queue is not empty:
Dequeue the next node from the queue.
If the node has not been visited:
Mark the node as visited.
Enqueue all of its neighbors.
Return the visited nodes.

Python Implementation of Breadth-First Search

To implement BFS in Python, we can start by creating a Graph class that will represent our graph. This class will have two main components: a list of nodes and a dictionary of adjacency lists. The list of nodes will contain all the nodes in the graph, and the dictionary of adjacency lists will map each node to its list of neighboring nodes.

class Graph:
def __init__(self):
self.nodes = []
self.adj_list = {}

Next, we will add a method to the Graph class to add a new node to the graph. This method will take a node object as an argument and append it to the list of nodes.

class Graph:
def __init__(self):
self.nodes = []
self.adj_list = {}

def add_node(self, node):
self.nodes.append(node)
self.adj_list[node] = []

We will then add a method to the Graph class to add an edge between two nodes. This method will take two node objects as arguments and add each node to the other node’s list of neighboring nodes.

class Graph:
def __init__(self):
self.nodes = []
self.adj_list = {}

def add_node(self, node):
self.nodes.append(node)
self.adj_list[node] = []

def add_edge(self, node1, node2):
self.adj_list[node1].append(node2)
self.adj_list[node2].append(node1)

Now that we have our Graph class set up, we can move on to implementing the BFS algorithm. We will create a function called bfs that takes two arguments: the starting node and the graph object.

def bfs(start, graph):
visited = set()
queue = []

visited.add(start)
queue.append(start)

while queue:
node = queue.pop(0)
print(node)

for neighbor in graph.adj_list[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)

In this function, we start by initializing a set to keep track of visited nodes and a queue to store the nodes that need to be explored. We then add the starting node to the visited set and enqueue it into the queue.

Next, we enter a loop that continues until the queue is empty. In each iteration of the loop, we dequeue the next node from the front of the queue and print its value. We then loop through all of its neighboring nodes and add them to the queue if they have not been visited yet.

Finally, we can test our BFS algorithm by creating a simple graph and calling the bfs function with a starting node.

g = Graph()

node1 = "A"
node2 = "B"
node3 = "C"
node4 = "D"
node5 = "E"

g.add_node(node1)
g.add_node(node2)
g.add_node(node3)
g.add_node(node4)
g.add_node(node5)

g.add_edge(node1, node2)
g.add_edge(node1, node3)
g.add_edge(node2, node4)
g.add_edge(node2, node5)
g.add_edge(node3, node5)

bfs(node1, g)

This will output the following:

A
B
C
D
E

of the loop, we dequeue the next node from the front of the queue and print its value. We then loop through all of its neighboring nodes and add them to the queue if they have not been visited yet.

Finally, we can test our BFS algorithm by creating a simple graph and calling the bfs function with a starting node.

g = Graph()

node1 = "A"
node2 = "B"
node3 = "C"
node4 = "D"
node5 = "E"

g.add_node(node1)
g.add_node(node2)
g.add_node(node3)
g.add_node(node4)
g.add_node(node5)

g.add_edge(node1, node2)
g.add_edge(node1, node3)
g.add_edge(node2, node4)
g.add_edge(node2, node5)
g.add_edge(node3, node5)

bfs(node1, g)

This will output the following:

A
B
C
D
E

This output shows that the BFS algorithm started at node “A” and explored all nodes in the graph in a level-by-level order, visiting node “B” and “C” at level 1, and nodes “D” and “E” at level 2.

Optimizations for Breadth-First Search

One optimization for the BFS algorithm is to use a visited set to keep track of visited nodes instead of a boolean array. This can be more memory-efficient if the graph is very large.

Another optimization is to use a deque data structure instead of a list to implement the queue. This allows for efficient adding and removing of elements from both ends of the deque.

Conclusion

In this article, we have explored the Breadth-First Search algorithm and how to implement it in Python. We started by creating a Graph class to represent our graph, then added methods to add nodes and edges to the graph. We then implemented the BFS algorithm using a queue data structure to store nodes that need to be explored. Finally, we tested our implementation on a simple graph and explored some optimizations for the algorithm.

BFS is a fundamental algorithm used in many applications and is a good starting point for exploring graph algorithms. By understanding the principles behind BFS and other graph algorithms, we can gain insight into more complex algorithms and data structures used in computer science.

--

--

Gennadiy Shevtsov

My journey through the realms of programming has led me to establish a dynamic digital haven:https://omniscopelife.com/