Implementation of Graph in C (original) (raw)

Last Updated : 12 Dec, 2024

Graphs are a versatile data structure that can be used to represent various real-world problems, from social networks to transportation systems. In C, graphs are typically represented using arrays for adjacency matrices or linked lists for adjacency lists. This article will introduce the concept of graphs, their representation in C using pointers and structures, and basic algorithms to perform operations such as traversal, insertion, and deletion.

What is a Graph?

A graph is defined as a set of nodes that connects two or more nodes with edges often referred to as arcs. The use of graphs is common in modelling different systems in the world, like the social structures, transport structures as well the computer structures.

Components of a Graph

Types of Graphs

Representation of Graphs in C

There are various forms of graphs, but the more frequently used are:

  1. Adjacency Matrix
  2. Adjacency List

1. Adjacency Matrix Graph Representation

An adjacency matrix is a two-dimensional matrix used with graphs. It is more efficient that the adjacency list representation when the graph is dense and we need quick access frequently.

Algorithm for Creating Adjacency Matrix of a Graph

**Example:

Example Graph:
0 -- 1
| |
2 -- 3

Adjacency Matrix:
0 1 2 3
0 [0 1 1 0]
1 [1 0 0 1]
2 [1 0 0 1]
3 [0 1 1 0]

Implementing Basic Graph Operations on Adjacency Matrix Representation

Following are the basic graph operations on adjacency matrix representation of the graph:

Operation Description Time Complexity Space Complexity
Insertion Add a vertex or an edge O(V2) O(V2)
Deletion Remove a vertex or an edge O(V2) O(V2)
Searching Check if a vertex or an edge exists O(1) O(1)
Traversal Visit all vertices (BFS or DFS) O(V + E) O(V)

**Insertion Implementation

  1. Determine the source vertex (u) and the destination vertex (v) where you want to insert an edge.
  2. Use the vertices as indices to access the cell in the adjacency matrix, matrix[u][v].
  3. Assign a value (typically 1) to indicate an edge between u and v, matrix[u][v] = 1. If the graph is weighted, then insert the weight of the edge.
  4. If the graph is undirected, also insert an edge in the opposite direction, matrix[v][u] = 1.

**Deletion Implementation

  1. Determine the source vertex (u) and the destination vertex (v) where you want to remove an edge.
  2. Use the vertices as indices to access the cell in the adjacency matrix, matrix[u][v].
  3. Assign a value (typically 0) to indicate no edge between u and v, matrix[u][v] = 0.
  4. If the graph is undirected, also remove the edge in the opposite direction, matrix[v][u] = 0.

**Search Implementation

  1. Determine the source vertex (u) and the destination vertex (v) for which you want to check the existence of an edge.
  2. Use the vertices as indices to access the cell in the adjacency matrix, matrix[u][v].
  3. Evaluate the value at matrix[u][v]. If it’s 1 (or any non-zero value), an edge exists; if it’s 0, there is no edge.

**Traversal Implementation (BFS)

  1. Select a vertex to start the traversal from.
  2. Initialize a queue to keep track of vertices to visit.
  3. Add the starting vertex to the queue and mark it as visited.
  4. While the queue is not empty, repeat the following steps:
  1. Keep repeating step 4 until there are no more vertices left to visit.

**Traversal Implementation (DFS)

  1. **Function DFS: This is the main function that initiates the DFS traversal.
  1. **Function DFSUtil: This is a recursive utility function that performs the actual DFS traversal.

C Program to Implement Graph using Adjacency Matrix

C `

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

#define MAX 10 #define TRUE 1 #define FALSE 0

// Function prototypes void insertEdge(int graph[MAX][MAX], int u, int v); void deleteEdge(int graph[MAX][MAX], int u, int v); int searchEdge(int graph[MAX][MAX], int u, int v); void BFS(int graph[MAX][MAX], int start); void DFS(int graph[MAX][MAX], int start); void DFSUtil(int graph[MAX][MAX], int start, int visited[MAX]);

int main() { // Initialize adjacency matrix to 0 int graph[MAX][MAX] = { 0 };

// Add edges
insertEdge(graph, 0, 1);
insertEdge(graph, 0, 2);
insertEdge(graph, 1, 2);
insertEdge(graph, 2, 0);
insertEdge(graph, 2, 3);

// Perform BFS
printf("BFS starting from node 2:\n");
BFS(graph, 2);

// Perform DFS
printf("DFS starting from node 2:\n");
DFS(graph, 2);

return 0;

}

// Function to insert an edge into the graph void insertEdge(int graph[MAX][MAX], int u, int v) { // Set the edge from u to v graph[u][v] = 1; // Set the edge from v to u (undirected graph) graph[v][u] = 1; }

// Function to delete an edge from the graph void deleteEdge(int graph[MAX][MAX], int u, int v) { // Remove the edge from u to v graph[u][v] = 0; // Remove the edge from v to u (undirected graph) graph[v][u] = 0; }

// Function to search for an edge in the graph int searchEdge(int graph[MAX][MAX], int u, int v) { // Return the existence of edge u-v return graph[u][v]; }

// Function to perform BFS traversal void BFS(int graph[MAX][MAX], int start) { // Initialize visited array int visited[MAX] = { 0 }; int queue[MAX], front = 0, rear = 0;

// Mark the start node as visited and enqueue it
visited[start] = TRUE;
queue[rear++] = start;

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

    // Visit all the adjacent nodes
    for (int i = 0; i < MAX; i++) {
        if (graph[current][i] == 1 && !visited[i]) {
            visited[i] = TRUE;
            queue[rear++] = i;
        }
    }
}
printf("\n");

}

// Function to perform DFS traversal void DFS(int graph[MAX][MAX], int start) { // Initialize visited array int visited[MAX] = { 0 }; DFSUtil(graph, start, visited); printf("\n"); }

// Utility function for DFS traversal void DFSUtil(int graph[MAX][MAX], int start, int visited[MAX]) { // Mark the current node as visited and print it visited[start] = TRUE; printf("%d ", start);

// Visit all the adjacent nodes
for (int i = 0; i < MAX; i++) {
    if (graph[start][i] == 1 && !visited[i]) {
        DFSUtil(graph, i, visited);
    }
}

}

`

Output

BFS starting from node 2: 2 0 1 3 DFS starting from node 2: 2 0 1 3

2. Adjacency List Graph Representation

The adjacency list is a concept in Graph Theory which describes the graph in terms of the array of the linked list. In the context of the given array, each element denotes a vertex and the linked list present at the same index contains all the vertices that are directly connected to the vertex represented by the given element.

**Example

Example Graph:
0 -- 1
| |
2 -- 3

Adjacency List:
0: -> 1 -> 2
1: -> 0 -> 3
2: -> 0 -> 3
3: -> 1 -> 2

Implementing Basic Graph Operations on Adjacency List Representation

Following are the basic operations of graph on adjacency list representation:

Operation Description Time Complexity Space Complexity
Insertion Add a vertex or an edge O(1) O(V)
Deletion Remove a vertex or an edge O(V) O(V)
Searching Check if a vertex or an edge exists O(V) O(1)
Traversal Visit all vertices (BFS or DFS) O(V + E) O(V)

**Insertion Implementation

**Deletion Implementation

**Search **Implementation

**Traversal Implementation (DFS)

**Traversal Implementation (BFS)

C Program to Implement Graph using Adjacency List

C `

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

// Define the structure for an adjacency list node struct AdjListNode { int dest; struct AdjListNode* next; };

// Define the structure for an adjacency list struct AdjList { struct AdjListNode* head; };

// Define the structure for a graph struct Graph { int V; struct AdjList* array; };

// Function to create a new adjacency list node struct AdjListNode* newAdjListNode(int dest) { struct AdjListNode* newNode = (struct AdjListNode*)malloc( sizeof(struct AdjListNode)); newNode->dest = dest; newNode->next = NULL; return newNode; }

// Function to create a graph of V vertices struct Graph* createGraph(int V) { struct Graph* graph = (struct Graph*)malloc(sizeof(struct Graph)); graph->V = V; graph->array = (struct AdjList*)malloc( V * sizeof(struct AdjList)); for (int i = 0; i < V; ++i) graph->array[i].head = NULL; return graph; }

// Function to add an edge to an undirected graph void addEdge(struct Graph* graph, int src, int dest) { // Add an edge from src to dest struct AdjListNode* newNode = newAdjListNode(dest); newNode->next = graph->array[src].head; graph->array[src].head = newNode;

// Since graph is undirected, add an edge from dest to
// src also
newNode = newAdjListNode(src);
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;

}

// Function to delete an edge from an undirected graph void deleteEdge(struct Graph* graph, int src, int dest) { struct AdjListNode* temp = graph->array[src].head; struct AdjListNode* prev = NULL;

// Find and remove the node from the adjacency list of
// src
while (temp != NULL && temp->dest != dest) {
    prev = temp;
    temp = temp->next;
}
if (temp != NULL) {
    if (prev != NULL)
        prev->next = temp->next;
    else
        graph->array[src].head = temp->next;
    free(temp);
}

// Since graph is undirected, remove the src from dest's
// list
temp = graph->array[dest].head;
prev = NULL;
while (temp != NULL && temp->dest != src) {
    prev = temp;
    temp = temp->next;
}
if (temp != NULL) {
    if (prev != NULL)
        prev->next = temp->next;
    else
        graph->array[dest].head = temp->next;
    free(temp);
}

}

// Function to search an edge in the graph int searchEdge(struct Graph* graph, int src, int dest) { struct AdjListNode* temp = graph->array[src].head; while (temp != NULL) { if (temp->dest == dest) return 1; // Found temp = temp->next; } return 0; // Not Found }

// A utility function used by DFS void DFSUtil(int v, int visited[], struct Graph* graph) { visited[v] = 1; printf("%d ", v);

struct AdjListNode* temp = graph->array[v].head;
while (temp) {
    int adjVertex = temp->dest;
    if (!visited[adjVertex])
        DFSUtil(adjVertex, visited, graph);
    temp = temp->next;
}

}

// Function to perform DFS on the graph void DFS(struct Graph* graph, int startVertex) { int* visited = (int*)malloc(graph->V * sizeof(int)); for (int i = 0; i < graph->V; i++) visited[i] = 0;

DFSUtil(startVertex, visited, graph);
free(visited);

}

// Function to perform BFS on the graph void BFS(struct Graph* graph, int startVertex) { int* visited = (int*)malloc(graph->V * sizeof(int)); for (int i = 0; i < graph->V; i++) visited[i] = 0;

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

visited[startVertex] = 1;
queue[rear++] = startVertex;

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

    struct AdjListNode* temp
        = graph->array[currentVertex].head;
    while (temp) {
        int adjVertex = temp->dest;
        if (!visited[adjVertex]) {
            visited[adjVertex] = 1;
            queue[rear++] = adjVertex;
        }
        temp = temp->next;
    }
}

free(queue);
free(visited);

}

int main() { // Create the graph given in above figure int V = 5; struct Graph* graph = createGraph(V); addEdge(graph, 0, 1); addEdge(graph, 0, 4); addEdge(graph, 1, 2); addEdge(graph, 1, 3); addEdge(graph, 1, 4); addEdge(graph, 2, 3); addEdge(graph, 3, 4);

printf("Following is Depth First Traversal (starting "
       "from vertex 0)\n");
DFS(graph, 0);

printf("\nFollowing is Breadth First Traversal "
       "(starting from vertex 0)\n");
BFS(graph, 0);

printf("\nSearching for edge 1-3: %s\n",
       searchEdge(graph, 1, 3) ? "Found" : "Not Found");
deleteEdge(graph, 1, 3);

printf("Searching for edge 1-3 after deletion: %s\n",
       searchEdge(graph, 1, 3) ? "Found" : "Not Found");

return 0;

}

`

**Output

Following is Depth First Traversal (starting from vertex 0)
0 4 3 2 1
Following is Breadth First Traversal (starting from vertex 0)
0 4 1 3 2
Searching for edge 1-3: Found
Searching for edge 1-3 after deletion: Not Found