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
Building on the concepts of efficient range queries, we now introduce the Fenwick Tree, also known as a Binary Indexed Tree (BIT). Developed by Peter Fenwick in 1994, this data structure provides a concise and efficient way to handle two common operations on an array: getting the prefix sum (sum of elements up to an index) and updating individual elements, both in logarithmic time. While Segment Trees are more versatile for various range operations, BITs are often simpler to implement and have better constant factors for prefix sums and point updates.
A Fenwick Tree is an array-based data structure that allows for efficient calculation of prefix sums and point updates. Its elegance lies in leveraging the binary representation of indices to determine which array elements affect which parts of the sum.
This clever indexing scheme ensures that both querying a prefix sum and updating an element involve traversing only O(log N) elements in the BIT array.
A Fenwick Tree primarily supports:
To update an element `arr[idx]` by adding `val` to it (or setting it to a new value, by adding the difference), we need to update all BIT array elements that cover `arr[idx]`.
// Global array for Fenwick Tree (1-indexed)
int BIT[MAX_SIZE + 1];
int N; // Size of original array
// Adds 'val' to element at 'idx' (0-indexed in original array)
void update(int idx, int val) {
idx = idx + 1; // Convert to 1-indexed
while (idx <= N) {
BIT[idx] += val;
idx += (idx & -idx); // Move to next relevant index (parent)
}
}
Time Complexity: O(log N) for each update.
To get the sum of elements from index 0 to `idx` (inclusive) in the original array, we query the BIT.
// Gets sum of elements from 0 to 'idx' (0-indexed in original array)
int query(int idx) {
idx = idx + 1; // Convert to 1-indexed
int sum = 0;
while (idx > 0) {
sum += BIT[idx];
idx -= (idx & -idx); // Move to previous relevant index
}
return sum;
}
Time Complexity: O(log N) for each query.
While BITs inherently provide prefix sums, a range sum `sum(L, R)` (sum of elements from index L to R) can be easily derived using two prefix sum queries:
`sum(L, R) = query(R) - query(L-1)`
A Fenwick Tree (BIT) visualization for an array. Each node `BIT[i]` stores the sum of a range, determined by the lowest set bit of `i`. For instance, `BIT[4]` stores the sum of `Arr[0]` to `Arr[3]`.
Advantages:
Disadvantages:
Fenwick Trees, due to their efficiency for prefix sums and updates, can be valuable for specific data analytics and tracking features on a platform like UdaanPath:
Our journey through data structures continues with the powerful Heap & Priority Queues. We'll explore how these specialized tree-based structures efficiently manage elements based on their priority, enabling quick retrieval of the minimum or maximum element, which is crucial for algorithms like Dijkstra's and Prim's, and for managing task scheduling.