Back

Graph Traversal in Data Structures: Types and Applications

06 Dec 2024
6 min read

Graph traversal refers to the process of visiting all the nodes in a graph systematically. Traversing a graph is crucial in many real-world applications, as it enables efficient searching, data retrieval, and graph-based decision-making. Two of the most commonly used techniques for graph traversal are Breadth-First Search (BFS) and Depth-First Search (DFS). These algorithms are fundamental to various applications. In this article, we will explore graph traversal types, applications, advantages, and examples.

What is Graph Traversal in Data Structure?

Graph traversal is the process of visiting all the vertices of a graph in a specific order. The primary goal of graph traversal is to explore all the nodes and edges in a graph, which helps in tasks such as finding the shortest path, detecting cycles, or searching for specific information.

Types of Graph Traversal Techniques

There are two primary types of graph traversal techniques:

1. Breadth-First Search (BFS)

BFS is a graph traversal technique that explores all the neighboring nodes at the present depth level before moving on to nodes at the next depth level. It starts from a given node, visits all its adjacent nodes, and continues this process level by level. BFS is particularly useful for finding the shortest path in an unweighted graph.

custom img

How BFS Works

  • Initialize the queue.
  • Start from visiting the source node, and mark it as visited.
  • Enqueue all unvisited adjacent nodes of the source node.
  • Nodes can be dequeued from the queue and visited.
  • A node dequeued will queue its unvisited adjacent nodes.
  • Steps 4 and 5 should be repeated until the queue is empty.

Time and Space Complexity

  • Time complexity: O (V + E)
  • Space complexity: O(V)

2. Depth-First Search (DFS)

This is a basic algorithm used to explore graph structures. It starts at the root node (selecting some arbitrary node as the root node in the case of a graph) and explores as far as possible along each branch before backtracking.

custom img

How DFS Works

  • Start with an empty stack and an empty visited list.
  • Push the initial vertex (starting vertex) onto the stack.
  • While the stack is not empty: some text
    • Pop the top vertex from the stack.
    • If the vertex has not been visited, add it to the visited list.
    • Push all unvisited adjacent vertices of the current vertex onto the stack.
  • The process continues until the stack is empty.

Time and Space Complexity of DFS 

  • Time complexity: O (V + E)
  • Space complexity: O(V)

Advantages of Graph Traversal

Here are the advantages of graph traversal:

  • The BFS algorithm helps in finding the shortest path in an unweighted graph.
  • DFS is more memory efficient than BFS as it doesn't need to store all the nodes at the current level.
  • Both BFS and DFS can be used to explore all nodes of a graph systematically, ensuring complete traversal.

Disadvantages of Graph Traversal

Here are the disadvantages of graph traversal:

  • The BFS is not ideal for deep graph traversal or pathfinding in weighted graphs.
  • DFS can get stuck in infinite loops if the graph contains cycles unless cycle detection is implemented.

Applications of Graph Traversal

Here are some of the applications of how graph traversal is used in real-world scenarios:

  • Graph traversal is used to analyze social networks, identify communities, and detect influential users.
  • Graph traversal is used in search engines to index and rank web pages.
  • GPS navigation systems use graph traversal to find the shortest path between two points.
  • Graph traversal is used to optimize database queries and improve query performance.
  • Amazon’s recommendation system uses graph traversal to suggest products based on user interactions and preferences.

Examples Program of BFS and DFS in C Language

Here are the example programs of BFS and DFS in C programming:

BFS

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// Structure for the graph
struct Graph {
    int V;
    int **adjMatrix;
};

// Function to create a graph with V vertices
struct Graph* createGraph(int V) {
    struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph));
    graph->V = V;
    graph->adjMatrix = (int**)malloc(V * sizeof(int*));

    for (int i = 0; i < V; i++) {
        graph->adjMatrix[i] = (int*)malloc(V * sizeof(int));
        for (int j = 0; j < V; j++) {
            graph->adjMatrix[i][j] = 0; // Initialize all edges as 0 (no edges)
        }
    }
    return graph;
}

// Function to add an edge to the graph (undirected graph)
void addEdge(struct Graph* graph, int src, int dest) {
    graph->adjMatrix[src][dest] = 1;
    graph->adjMatrix[dest][src] = 1;
}

// Function to perform BFS traversal
void BFS(struct Graph* graph, int start) {
    bool* visited = (bool*)malloc(graph->V * sizeof(bool));
    for (int i = 0; i < graph->V; i++) {
        visited[i] = false;
    }

    int* queue = (int*)malloc(graph->V * sizeof(int));
    int front = 0, rear = 0;

    visited[start] = true;
    queue[rear++] = start;

    while (front != rear) {
        int node = queue[front++];
        printf("%d ", node);

        for (int i = 0; i < graph->V; i++) {
            if (graph->adjMatrix[node][i] == 1 && !visited[i]) {
                visited[i] = true;
                queue[rear++] = i;
            }
        }
    }

    free(visited);
    free(queue);
}

int main() {
    struct Graph* graph = createGraph(6);
    
    addEdge(graph, 0, 1);
    addEdge(graph, 0, 2);
    addEdge(graph, 1, 3);
    addEdge(graph, 1, 4);
    addEdge(graph, 2, 5);
    
    printf("BFS starting from vertex 0:\n");
    BFS(graph, 0);

    return 0;
}

DFS

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// Structure for the graph
struct Graph {
    int V;
    int **adjMatrix;
};

// Function to create a graph with V vertices
struct Graph* createGraph(int V) {
    struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph));
    graph->V = V;
    graph->adjMatrix = (int**)malloc(V * sizeof(int*));

    for (int i = 0; i < V; i++) {
        graph->adjMatrix[i] = (int*)malloc(V * sizeof(int));
        for (int j = 0; j < V; j++) {
            graph->adjMatrix[i][j] = 0; // Initialize all edges as 0 (no edges)
        }
    }
    return graph;
}

// Function to add an edge to the graph (undirected graph)
void addEdge(struct Graph* graph, int src, int dest) {
    graph->adjMatrix[src][dest] = 1;
    graph->adjMatrix[dest][src] = 1;
}

// Recursive function to perform DFS traversal
void DFS(struct Graph* graph, int node, bool* visited) {
    visited[node] = true;
    printf("%d ", node);

    for (int i = 0; i < graph->V; i++) {
        if (graph->adjMatrix[node][i] == 1 && !visited[i]) {
            DFS(graph, i, visited);
        }
    }
}

int main() {
    struct Graph* graph = createGraph(6);
    
    addEdge(graph, 0, 1);
    addEdge(graph, 0, 2);
    addEdge(graph, 1, 3);
    addEdge(graph, 1, 4);
    addEdge(graph, 2, 5);
    
    bool* visited = (bool*)malloc(graph->V * sizeof(bool));
    for (int i = 0; i < graph->V; i++) {
        visited[i] = false;
    }

    printf("DFS starting from vertex 0:\n");
    DFS(graph, 0, visited);

    free(visited);
    return 0;
}

Conclusion

In conclusion, graph traversal is a crucial operation in data structures. Both BFS and DFS are fundamental algorithms used for searching, exploring, and analyzing graphs. So, BFS is ideal for finding the shortest path and DFS is used for deeper nodes and solving problems. Understanding these traversal techniques and their complexities can help in optimizing graph-based operations and solving a wide range of computational problems.

Frequently Asked Questions

1. What is the difference between BFS and DFS in graph traversal?

BFS explores the graph level by level, ensuring the shortest path in an unweighted graph, while DFS explores as far down a branch as possible before backtracking, which can be more memory efficient but doesn’t guarantee the shortest path.

2. How BFS is used in binary trees?

In binary trees, BFS is also known as level-order traversal which visits all the nodes at the present level before moving on to the next level, which is useful for tasks like printing the tree level by level.

3. How do BFS and DFS work with graphs in data structures?

Both BFS and DFS explore all nodes and edges of a graph. BFS explores level by level, while DFS explores deeper paths before backtracking, with each having unique use cases based on the problems.

Read More Articles

Chat with us
Chat with us
Talk to career expert