This course is designed to help learners master the core concepts of Data Structures and Algorithms (DSA) using the C programming language. Starting from the basics and advancing to complex topics like graphs, dynamic programming, and memory optimization, this course is ideal for students, job seekers, and aspiring developers. You’ll learn how to structure and manipulate data efficiently, solve real-world coding problems, and prepare for technical interviews at top companies. The content is structured step-by-step, combining theory with hands-on coding examples and practice problems to reinforce understanding. Whether you're preparing for university exams, campus placements, or competitive programming, this course provides a strong foundation in logic building, code efficiency, and problem-solving using C. Key Highlights: Covers all major DSA topics from beginner to advanced level 100+ coding examples with explanations Focus on time and space complexity optimization Designed for coding interviews, competitive exams, and CS fundamentals
Welcome to the realm of graphs! A graph is a fundamental, non-linear data structure that consists of a set of interconnected entities. Think of it as a network of points (or nodes) linked together by lines (or edges). Graphs are everywhere in the real world: social networks, road maps, the internet, airline routes, and even dependencies between tasks in a project.
To apply algorithms to graphs, we first need a systematic way to store them in computer memory. The two most common ways are **Adjacency Matrix** and **Adjacency List**.
An Adjacency Matrix represents a graph as a 2D array (or matrix) of size $V \times V$, where $V$ is the number of vertices.
Example: Undirected Graph (4 Vertices, 4 Edges)
Adjacency Matrix Representation
For an undirected graph, `matrix[i][j]` is 1 if there's an edge between i and j. Note the symmetry.
// Conceptual C++ for Adjacency Matrix
const int MAX_VERTICES = 100;
int adjMatrix[MAX_VERTICES][MAX_VERTICES]; // For unweighted graph
// Initialize (all 0s)
void init_matrix(int V) {
for (int i = 0; i < V; ++i) {
for (int j = 0; j < V; ++j) {
adjMatrix[i][j] = 0;
}
}
}
// Add an undirected edge
void add_edge_matrix(int u, int v) {
adjMatrix[u][v] = 1;
adjMatrix[v][u] = 1; // For undirected
}
// Check if edge exists
bool has_edge_matrix(int u, int v) {
return adjMatrix[u][v] == 1;
}
An Adjacency List represents a graph as an array of lists (or vectors in C++, ArrayLists in Java, etc.). The size of the array is $V$.
Adjacency List Representation (for the same graph)
Each list shows the direct neighbors of a vertex. For undirected graphs, if (u,v) is an edge, both u's list contains v and v's list contains u.
// Conceptual C++ for Adjacency List
const int MAX_VERTICES_AL = 100;
vector<int> adjList[MAX_VERTICES_AL]; // Array of vectors for unweighted
// Add an undirected edge
void add_edge_list(int u, int v) {
adjList[u].push_back(v);
adjList[v].push_back(u); // For undirected
}
// Check if edge exists (less efficient than matrix)
bool has_edge_list(int u, int v) {
for (int neighbor : adjList[u]) {
if (neighbor == v) return true;
}
return false;
}
| Feature | Adjacency Matrix | Adjacency List |
|---|---|---|
| Space Complexity | $O(V^2)$ | $O(V + E)$ |
| Edge Check $(u, v)$ | $O(1)$ | $O(\text{degree}(u))$ or $O(V)$ worst case |
| Iterate Neighbors of $u$ | $O(V)$ | $O(\text{degree}(u))$ |
| Best For | Dense graphs ($E \approx V^2$), frequent edge checks. | Sparse graphs ($E \ll V^2$), frequent neighbor iteration (e.g., BFS/DFS). |
Choosing between them depends on the graph's density (how many edges it has relative to the maximum possible) and the types of operations you'll perform most frequently. For competitive programming, Adjacency List is generally preferred because most graphs given are sparse.
Graphs are fundamental to how a platform like UdaanPath might manage and process relationships:
Now that we know how to store graphs, it's time to learn how to explore them! Our next chapter will delve into the two most fundamental graph traversal algorithms: Breadth-First Search (BFS) and Depth-First Search (DFS). These algorithms are the backbone for solving countless graph problems.