Ai Lab
Ai Lab
Theory
Tree traversal is a key concept in data structures that involves systematically visiting all nodes of a
tree. This process is essential for tasks like searching, updating, or displaying the elements of the
tree.
Description:
BFS is a graph traversal technique that processes nodes level by level. Starting from the root
(or any chosen node), it explores all adjacent nodes at the current depth before progressing
to nodes at the next depth level.
Use Case:
Level Order Traversal: This approach is used in trees to visit all nodes at a specific level
before moving on to the next level.
Completeness:
Time Complexity:
O(b^d), where b is the branching factor, and d is the depth of the shallowest solution.
Space Complexity:
Description:
DFS is a graph traversal algorithm that explores as deep as possible along one path before
backtracking to explore other paths. Unlike BFS, it prioritizes depth over breadth.
1. Preorder: Visit the node first, then its left child, and then its right child.
Order: Root → Left Subtree → Right Subtree.
2. Inorder: Visit the left child first, then the node, and finally the right child.
Order: Left Subtree → Root → Right Subtree.
3. Postorder: Visit the left child, then the right child, and finally the node.
Order: Left Subtree → Right Subtree → Root.
Completeness:
DFS is not guaranteed to be complete, as it may get stuck in infinite-depth spaces or cycles.
Time Complexity:
O(b^m), where b is the branching factor, and mmm is the maximum depth of the search tree.
Space Complexity:
O(bm), requiring linear space proportional to the depth of the search tree.
Code:
#include <iostream>
#include <queue>
struct TreeNode {
int value;
TreeNode* left;
TreeNode* right;
TreeNode(int val) {
value = val;
left = nullptr;
right = nullptr;
};
// Function to insert nodes in the tree level-wise
TreeNode* createTree() {
cout << "Enter the root value (or -1 for no node): ";
int rootValue;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
q.pop();
cout << "Enter left child of " << current->value << " (or -1 for no node): ";
if (leftValue != -1) {
q.push(current->left);
cout << "Enter right child of " << current->value << " (or -1 for no node): ";
if (rightValue != -1) {
return root;
if (root == nullptr) {
return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
q.pop();
if (current->left != nullptr) {
q.push(current->left);
if (current->right != nullptr) {
q.push(current->right);
}
}
int main() {
BFS(root);
return 0;
Output:
Working:
1. BFS starts with the root node (1). It is added to the queue and processed first.
Queue: [1] → Process: 1 → Output: 1
2. The neighbors (children) of node 1, which are 2 and 3, are added to the queue.
Queue: [2, 3] → Process: 2 → Output: 1, 2
3. The neighbors (children) of node 2, which are 4 and 5, are added to the queue.
Queue: [3, 4, 5] → Process: 3 → Output: 1, 2, 3
4. Node 3 has no children, so the next node in the queue (4) is processed.
Queue: [4, 5] → Process: 4 → Output: 1, 2, 3, 4
5. Finally, node 5 is processed. It has no children, and the queue becomes empty.
Queue: [5] → Process: 5 → Output: 1, 2, 3, 4, 5
Applications of BFS
1. Shortest Path in Unweighted Graphs: Efficiently finds the minimum edges between two
nodes.
5. Web Crawlers: Explores all reachable links starting from a given page.
BFS provides a structured and efficient approach for traversing graphs and trees.
Code:
#include <iostream>
#include <queue>
struct TreeNode {
int value;
TreeNode* left;
TreeNode* right;
TreeNode(int val) {
value = val;
left = nullptr;
right = nullptr;
};
// Function to build a binary tree from user input
TreeNode* buildTree() {
cout << "Enter the root value (-1 for no node): ";
int rootValue;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
q.pop();
cout << "Enter left child of " << current->value << " (-1 for no node): ";
if (leftValue != -1) {
q.push(current->left);
cout << "Enter right child of " << current->value << " (-1 for no node): ";
if (rightValue != -1) {
q.push(current->right);
}
return root;
DFS_Preorder(root->left);
DFS_Preorder(root->right);
DFS_Inorder(root->left);
DFS_Inorder(root->right);
DFS_Postorder(root->left);
DFS_Postorder(root->right);
int main() {
cout << "Build your binary tree:\n";
DFS_Preorder(root);
DFS_Inorder(root);
DFS_Postorder(root);
return 0;
Output:
Working:
Visit the node first, then recursively traverse the left subtree, followed by the right subtree.
Steps:
Output: 1, 2, 4, 5, 3
Recursively traverse the left subtree, visit the node, then traverse the right subtree.
Steps:
1. Traverse left subtree of 1: Traverse left subtree of 2 (Visit node 4) → Visit node 2 → Visit
node 5.
Output: 4, 2, 5, 1, 3
Recursively traverse the left subtree, then the right subtree, and visit the node at the end.
Steps:
1. Traverse left subtree of 1: Traverse left subtree of 2 (Visit node 4) → Visit node 5 → Visit
node 2.
2. Traverse right subtree of 1: Visit node 3.
Output: 4, 5, 2, 3, 1
1. Preorder Traversal:
2. Inorder Traversal:
3. Postorder Traversal:
DFS facilitates efficient exploration of binary trees and solving tree-related problems.
Conclusion
In this experiment, we examined the functionality and implementation of two graph traversal
techniques, Breadth-First Search (BFS) and Depth-First Search (DFS). BFS traverses a graph or tree
level by level, exploring all nodes at the current depth before moving to the next. It uses a queue
data structure to track the nodes to visit, making it ideal for applications like finding the shortest path
in an unweighted graph or performing level-order traversal in trees. On the other hand, DFS explores
as deeply as possible along each branch before backtracking, utilizing either recursion or an explicit
stack. It supports three traversal orders—pre-order, in-order, and post-order—and is commonly
used for tasks like pathfinding, cycle detection, and analyzing hierarchical structures. While BFS
processes nodes horizontally, requiring more memory for nodes at the current level, DFS explores
vertically and requires memory proportional to the depth. BFS guarantees finding the shortest path
in unweighted graphs, whereas DFS does not ensure optimal paths. Together, these techniques offer
versatile approaches to solving various computational problems.