Complete Notes on Data Structures in C

With Code Examples, Structures, and Detailed Explanations

Complete Notes on Data Structures in C

With Code Examples, Structures, and Detailed Explanations

Complete Notes on Data Structures in C

With Code Examples, Structures, and Detailed Explanations


1. Introduction

Basic Terminology

  • Data: Raw facts or values (e.g., numbers, characters).
  • Information: Processed and meaningful data.
  • Data Structure: A way to organize and store data in a computer so it can be used efficiently.
  • Algorithm: A step-by-step procedure to solve a problem.

Elementary Data Organization

Type Description
Primitive Basic types: int, char, float, double
Non-Primitive Derived from primitive: Arrays, Structures, Pointers, etc.

Built-in Data Types in C

Type Size (Typical) Range
char 1 byte -128 to 127
int 4 bytes -2³¹ to 2³¹−1
float 4 bytes ±3.4E-38 to ±3.4E+38
double 8 bytes ±1.7E-308 to ±1.7E+308
void Represents no value

2. Algorithm & Efficiency

Algorithm

A finite sequence of well-defined instructions to solve a problem.

int linearSearch(int arr[], int n, int key) {
    for(int i = 0; i < n; i++) {
        if(arr[i] == key)
            return i;
    }
    return -1;
}

Efficiency of an Algorithm

Measured using:
- Time Complexity: How runtime grows with input size.
- Space Complexity: How memory usage grows with input size.


Asymptotic Notations

Notation Meaning Example
Big-O (O) Upper bound (worst case) O(n)
Big-Ω (Ω) Lower bound (best case) Ω(1)
Big-Θ (Θ) Tight bound (average case) Θ(n²)

Common Complexities

Complexity Name
O(1) Constant
O(log n) Logarithmic
O(n) Linear
O(n log n) Linearithmic
O(n²) Quadratic
O(2ⁿ) Exponential

Time-Space Trade-off

Increase space usage to reduce time (or vice versa).

Example: Precompute factorial values in an array → O(1) lookup vs O(n) computation.

long long fact[100];
void precompute() {
    fact[0] = 1;
    for(int i = 1; i < 100; i++)
        fact[i] = fact[i-1] * i;
}

3. Abstract Data Types (ADT)

ADT = Mathematical model + Operations
Focus on what it does, not how it's implemented.

ADT Operations
List Insert, Delete, Search, Traverse
Stack Push, Pop, Peek
Queue Enqueue, Dequeue

4. Arrays

Definition

A collection of elements of the same type stored in contiguous memory.


Single Dimensional Array

int arr[5] = {10, 20, 30, 40, 50};

Structure

Index:     0    1    2    3    4
         +----+----+----+----+----+
Value:   | 10 | 20 | 30 | 40 | 50 |
         +----+----+----+----+----+
Address: 1000 1004 1008 1012 1016

Multidimensional Arrays

2D Array (Matrix)

int mat[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10,11,12}
};
Memory Layout: Row-Major Order

Elements stored row by row.

Address Calculation:
For mat[i][j]:
Address = Base + (i * COLS + j) * size_of_element
Column-Major Order

Elements stored column by column (used in Fortran).

Address = Base + (j * ROWS + i) * size_of_element

Index Formula Derivation

1D Array

Address(a[i]) = Base + i * size

2D Array (Row-Major)

Let ROWS = m, COLS = n
Address(a[i][j]) = Base + (i * n + j) * size

3D Array (Row-Major)

Dimensions: [l][m][n]
Address(a[i][j][k]) = Base + ((i * m + j) * n + k) * size

nD Array (General Formula - Row-Major)

Address = Base + (i₁*c₂*...*cₙ + i₂*c₃*...*cₙ + ... + iₙ₋₁*cₙ + iₙ) * size

Applications of Arrays

  • Storing lists (marks, names)
  • Matrix operations
  • Polynomial representation
  • Lookup tables

Sparse Matrix

A matrix with most elements zero.

Example:

0 0 5 0
0 0 0 0
2 0 0 0

Compact Representation (Triplet Form)

Row Col Value
0 2 5
2 0 2
struct Sparse {
    int row, col, value;
};

struct Sparse matrix[100];
int total_non_zero = 2;

5. Linked Lists

Dynamic data structure where elements are connected via pointers.


Types of Linked Lists

Type Description
Singly One direction (next)
Doubly Two directions (prev, next)
Circular Last → First

Singly Linked List

Node Structure

struct Node {
    int data;
    struct Node* next;
};

Diagram

HEAD → [10 | →] → [20 | →] → [30 | NULL]

Code: Insertion at Beginning

struct Node* insertFront(struct Node* head, int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = head;
    return newNode;
}

Traversal

void printList(struct Node* head) {
    struct Node* temp = head;
    while(temp != NULL) {
        printf("%d → ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

Deletion (by value)

struct Node* deleteNode(struct Node* head, int key) {
    struct Node *temp = head, *prev = NULL;

    if(temp != NULL && temp->data == key) {
        head = temp->next;
        free(temp);
        return head;
    }

    while(temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if(temp == NULL) return head;

    prev->next = temp->next;
    free(temp);
    return head;
}

Doubly Linked List

Node

struct DNode {
    int data;
    struct DNode *prev, *next;
};

Diagram

NULL ← [10|↔] ↔ [20|↔] ↔ [30|→] NULL

Insertion at End

void insertEnd(struct DNode** head, int data) {
    struct DNode* newNode = (struct DNode*)malloc(sizeof(struct DNode));
    newNode->data = data;
    newNode->next = NULL;

    if(*head == NULL) {
        newNode->prev = NULL;
        *head = newNode;
        return;
    }

    struct DNode* temp = *head;
    while(temp->next != NULL)
        temp = temp->next;

    temp->next = newNode;
    newNode->prev = temp;
}

Circular Linked List

Singly Circular

[10|→] → [20|→] → [30|→]
  ↑_____________________|
void printCircular(struct Node* head) {
    if(head == NULL) return;
    struct Node* temp = head;
    do {
        printf("%d ", temp->data);
        temp = temp->next;
    } while(temp != head);
}

6. Polynomial Representation Using Linked List

Single Variable Polynomial

e.g., 3x⁴ + 2x² + 5

Node

struct Term {
    int coeff;
    int exp;
    struct Term* next;
};

Create Term

struct Term* createTerm(int c, int e) {
    struct Term* t = (struct Term*)malloc(sizeof(struct Term));
    t->coeff = c;
    t->exp = e;
    t->next = NULL;
    return t;
}

Add Two Polynomials

struct Term* addPoly(struct Term* p1, struct Term* p2) {
    struct Term *result = NULL, *temp, *last = NULL;

    while(p1 && p2) {
        if(p1->exp > p2->exp) {
            temp = createTerm(p1->coeff, p1->exp);
            p1 = p1->next;
        }
        else if(p2->exp > p1->exp) {
            temp = createTerm(p2->coeff, p2->exp);
            p2 = p2->next;
        }
        else {
            int sum = p1->coeff + p2->coeff;
            if(sum != 0) {
                temp = createTerm(sum, p1->exp);
            } else {
                temp = NULL;
            }
            p1 = p1->next;
            p2 = p2->next;
        }

        if(temp) {
            if(!result) result = temp;
            else last->next = temp;
            last = temp;
        }
    }

    // Append remaining terms
    struct Term* remaining = p1 ? p1 : p2;
    while(remaining) {
        temp = createTerm(remaining->coeff, remaining->exp);
        if(!result) result = temp;
        else last->next = temp;
        last = temp;
        remaining = remaining->next;
    }

    return result;
}

Two Variable Polynomial

e.g., 3x²y + 2xy² + 5x + 7

Node

struct Term2D {
    int coeff;
    int expX, expY;
    struct Term2D* next;
};

Summary Table

Feature Array Linked List
Memory Contiguous Non-contiguous
Access O(1) O(n)
Insertion/Deletion O(n) O(1) at known position
Size Fixed Dynamic

Key Takeaways

  1. Arrays → Fast access, fixed size, good for matrices.
  2. Linked Lists → Dynamic size, efficient insert/delete.
  3. Sparse Matrix → Save space using triplet form.
  4. Polynomials → Use linked list for variable degree.
  5. Complexity → Always analyze time and space.

Practice Tip: Implement all operations for singly, doubly, and circular linked lists. Solve polynomial addition/subtraction using linked lists.


End of Notes

Last updated: Nov 12, 2025

Complete Notes on Data Structures in C

With Code Examples, Structures, and Detailed Explanations

Complete Notes on Data Structures in C

With Code Examples, Structures, and Detailed Explanations

Complete Notes on Data Structures in C

With Code Examples, Structures, and Detailed Explanations


1. Introduction

Basic Terminology

  • Data: Raw facts or values (e.g., numbers, characters).
  • Information: Processed and meaningful data.
  • Data Structure: A way to organize and store data in a computer so it can be used efficiently.
  • Algorithm: A step-by-step procedure to solve a problem.

Elementary Data Organization

Type Description
Primitive Basic types: int, char, float, double
Non-Primitive Derived from primitive: Arrays, Structures, Pointers, etc.

Built-in Data Types in C

Type Size (Typical) Range
char 1 byte -128 to 127
int 4 bytes -2³¹ to 2³¹−1
float 4 bytes ±3.4E-38 to ±3.4E+38
double 8 bytes ±1.7E-308 to ±1.7E+308
void Represents no value

2. Algorithm & Efficiency

Algorithm

A finite sequence of well-defined instructions to solve a problem.

int linearSearch(int arr[], int n, int key) {
    for(int i = 0; i < n; i++) {
        if(arr[i] == key)
            return i;
    }
    return -1;
}

Efficiency of an Algorithm

Measured using:
- Time Complexity: How runtime grows with input size.
- Space Complexity: How memory usage grows with input size.


Asymptotic Notations

Notation Meaning Example
Big-O (O) Upper bound (worst case) O(n)
Big-Ω (Ω) Lower bound (best case) Ω(1)
Big-Θ (Θ) Tight bound (average case) Θ(n²)

Common Complexities

Complexity Name
O(1) Constant
O(log n) Logarithmic
O(n) Linear
O(n log n) Linearithmic
O(n²) Quadratic
O(2ⁿ) Exponential

Time-Space Trade-off

Increase space usage to reduce time (or vice versa).

Example: Precompute factorial values in an array → O(1) lookup vs O(n) computation.

long long fact[100];
void precompute() {
    fact[0] = 1;
    for(int i = 1; i < 100; i++)
        fact[i] = fact[i-1] * i;
}

3. Abstract Data Types (ADT)

ADT = Mathematical model + Operations
Focus on what it does, not how it's implemented.

ADT Operations
List Insert, Delete, Search, Traverse
Stack Push, Pop, Peek
Queue Enqueue, Dequeue

4. Arrays

Definition

A collection of elements of the same type stored in contiguous memory.


Single Dimensional Array

int arr[5] = {10, 20, 30, 40, 50};

Structure

Index:     0    1    2    3    4
         +----+----+----+----+----+
Value:   | 10 | 20 | 30 | 40 | 50 |
         +----+----+----+----+----+
Address: 1000 1004 1008 1012 1016

Multidimensional Arrays

2D Array (Matrix)

int mat[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10,11,12}
};
Memory Layout: Row-Major Order

Elements stored row by row.

Address Calculation:
For mat[i][j]:
Address = Base + (i * COLS + j) * size_of_element
Column-Major Order

Elements stored column by column (used in Fortran).

Address = Base + (j * ROWS + i) * size_of_element

Index Formula Derivation

1D Array

Address(a[i]) = Base + i * size

2D Array (Row-Major)

Let ROWS = m, COLS = n
Address(a[i][j]) = Base + (i * n + j) * size

3D Array (Row-Major)

Dimensions: [l][m][n]
Address(a[i][j][k]) = Base + ((i * m + j) * n + k) * size

nD Array (General Formula - Row-Major)

Address = Base + (i₁*c₂*...*cₙ + i₂*c₃*...*cₙ + ... + iₙ₋₁*cₙ + iₙ) * size

Applications of Arrays

  • Storing lists (marks, names)
  • Matrix operations
  • Polynomial representation
  • Lookup tables

Sparse Matrix

A matrix with most elements zero.

Example:

0 0 5 0
0 0 0 0
2 0 0 0

Compact Representation (Triplet Form)

Row Col Value
0 2 5
2 0 2
struct Sparse {
    int row, col, value;
};

struct Sparse matrix[100];
int total_non_zero = 2;

5. Linked Lists

Dynamic data structure where elements are connected via pointers.


Types of Linked Lists

Type Description
Singly One direction (next)
Doubly Two directions (prev, next)
Circular Last → First

Singly Linked List

Node Structure

struct Node {
    int data;
    struct Node* next;
};

Diagram

HEAD → [10 | →] → [20 | →] → [30 | NULL]

Code: Insertion at Beginning

struct Node* insertFront(struct Node* head, int data) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = head;
    return newNode;
}

Traversal

void printList(struct Node* head) {
    struct Node* temp = head;
    while(temp != NULL) {
        printf("%d → ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

Deletion (by value)

struct Node* deleteNode(struct Node* head, int key) {
    struct Node *temp = head, *prev = NULL;

    if(temp != NULL && temp->data == key) {
        head = temp->next;
        free(temp);
        return head;
    }

    while(temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    if(temp == NULL) return head;

    prev->next = temp->next;
    free(temp);
    return head;
}

Doubly Linked List

Node

struct DNode {
    int data;
    struct DNode *prev, *next;
};

Diagram

NULL ← [10|↔] ↔ [20|↔] ↔ [30|→] NULL

Insertion at End

void insertEnd(struct DNode** head, int data) {
    struct DNode* newNode = (struct DNode*)malloc(sizeof(struct DNode));
    newNode->data = data;
    newNode->next = NULL;

    if(*head == NULL) {
        newNode->prev = NULL;
        *head = newNode;
        return;
    }

    struct DNode* temp = *head;
    while(temp->next != NULL)
        temp = temp->next;

    temp->next = newNode;
    newNode->prev = temp;
}

Circular Linked List

Singly Circular

[10|→] → [20|→] → [30|→]
  ↑_____________________|
void printCircular(struct Node* head) {
    if(head == NULL) return;
    struct Node* temp = head;
    do {
        printf("%d ", temp->data);
        temp = temp->next;
    } while(temp != head);
}

6. Polynomial Representation Using Linked List

Single Variable Polynomial

e.g., 3x⁴ + 2x² + 5

Node

struct Term {
    int coeff;
    int exp;
    struct Term* next;
};

Create Term

struct Term* createTerm(int c, int e) {
    struct Term* t = (struct Term*)malloc(sizeof(struct Term));
    t->coeff = c;
    t->exp = e;
    t->next = NULL;
    return t;
}

Add Two Polynomials

struct Term* addPoly(struct Term* p1, struct Term* p2) {
    struct Term *result = NULL, *temp, *last = NULL;

    while(p1 && p2) {
        if(p1->exp > p2->exp) {
            temp = createTerm(p1->coeff, p1->exp);
            p1 = p1->next;
        }
        else if(p2->exp > p1->exp) {
            temp = createTerm(p2->coeff, p2->exp);
            p2 = p2->next;
        }
        else {
            int sum = p1->coeff + p2->coeff;
            if(sum != 0) {
                temp = createTerm(sum, p1->exp);
            } else {
                temp = NULL;
            }
            p1 = p1->next;
            p2 = p2->next;
        }

        if(temp) {
            if(!result) result = temp;
            else last->next = temp;
            last = temp;
        }
    }

    // Append remaining terms
    struct Term* remaining = p1 ? p1 : p2;
    while(remaining) {
        temp = createTerm(remaining->coeff, remaining->exp);
        if(!result) result = temp;
        else last->next = temp;
        last = temp;
        remaining = remaining->next;
    }

    return result;
}

Two Variable Polynomial

e.g., 3x²y + 2xy² + 5x + 7

Node

struct Term2D {
    int coeff;
    int expX, expY;
    struct Term2D* next;
};

Summary Table

Feature Array Linked List
Memory Contiguous Non-contiguous
Access O(1) O(n)
Insertion/Deletion O(n) O(1) at known position
Size Fixed Dynamic

Key Takeaways

  1. Arrays → Fast access, fixed size, good for matrices.
  2. Linked Lists → Dynamic size, efficient insert/delete.
  3. Sparse Matrix → Save space using triplet form.
  4. Polynomials → Use linked list for variable degree.
  5. Complexity → Always analyze time and space.

Practice Tip: Implement all operations for singly, doubly, and circular linked lists. Solve polynomial addition/subtraction using linked lists.


End of Notes

Last updated: Nov 12, 2025