C 7

Phase 7 — Data Structures & Algorithms in C

Phase 7 is where C moves from “I know the language” to “I can use the language to solve real problems.”

We’ll divide it logically into:

  1. Foundations of DSA

  2. Linear Data Structures

  3. Hash Tables

  4. Trees & Heaps

  5. Graphs

  6. Searching & Sorting

  7. Algorithmic Thinking & Complexity


Module 1 — DSA Foundations

Chapter 1 — What Is a Data Structure?

Question

The following program stores three numbers in an array and accesses the second element.

What is the output?

#include <stdio.h>

int main(void)
{
    // Store related values together.
    int numbers[] = {10, 20, 30};

    // Access the second element.
    printf("%d\n", numbers[1]);

    return 0;
}

Answer

20

Step-by-step explanation

  1. numbers is an array.

  2. It contains three integers:

index:    0    1    2
value:   10   20   30
  1. C arrays use zero-based indexing.

  2. Therefore numbers[1] means the second element.

  3. The result is 20.

How to read the important code

When you see:

int numbers[] = {10, 20, 30};

read it naturally as:

“Create an integer array containing 10, 20 and 30.”

A data structure is simply a way of organizing data so that operations on that data can be performed efficiently.

Examples:

Array
Linked List
Stack
Queue
Hash Table
Tree
Heap
Graph

Key takeaway

Data structure = a way of organizing and storing data.


Module 2 — Dynamic Arrays

Chapter 2 — Dynamic Arrays

Question

Predict the output.

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

int main(void)
{
    // Allocate space for three integers.
    int *numbers = malloc(3 * sizeof(int));

    // Store values dynamically.
    numbers[0] = 10;
    numbers[1] = 20;
    numbers[2] = 30;

    // Read the final element.
    printf("%d\n", numbers[2]);

    // Release the allocated memory.
    free(numbers);

    return 0;
}

Answer

30

Step-by-step explanation

malloc() creates memory dynamically.

malloc(3 * sizeof(int))

means:

“Give me enough heap memory to store three integers.”

Because numbers is a pointer, we can use array syntax:

numbers[0]
numbers[1]
numbers[2]

This is one of the most important C ideas:

An allocated block of memory can be used like an array through a pointer.

A dynamic array usually needs:

pointer → allocated memory
size    → number of elements currently stored
capacity → number of elements the allocation can hold

When capacity is exhausted, we can use realloc() to grow it.

Key takeaway

Dynamic arrays combine pointers, heap memory and array-style access.


Module 3 — Linked Lists

Chapter 3 — Singly Linked List

Question

Predict the output.

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

struct Node
{
    // Store the actual value.
    int data;

    // Point to the next node.
    struct Node *next;
};

int main(void)
{
    // Create two nodes dynamically.
    struct Node *first = malloc(sizeof(struct Node));
    struct Node *second = malloc(sizeof(struct Node));

    // Connect the nodes.
    first->data = 10;
    first->next = second;

    second->data = 20;
    second->next = NULL;

    // Traverse the list.
    printf("%d %d\n", first->data, first->next->data);

    // Free both nodes.
    free(second);
    free(first);

    return 0;
}

Answer

10 20

Step-by-step explanation

Each node contains:

+------+------+
| data | next |
+------+------+

The structure is:

first
  |
  v
+----+------+     +----+------+
| 10 | next | --> | 20 | NULL |
+----+------+     +----+------+

This line:

first->next->data

means:

  1. Go to first.

  2. Follow its next pointer.

  3. Reach the second node.

  4. Read its data.

-> is used when accessing a structure through a pointer.

Key takeaway

A linked list is a chain of nodes connected through pointers.


Chapter 4 — Doubly & Circular Linked Lists

Question

What does this print?

#include <stdio.h>

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

int main(void)
{
    struct Node a = {10, NULL, NULL};
    struct Node b = {20, NULL, NULL};

    // Connect a forward to b.
    a.next = &b;

    // Connect b backward to a.
    b.prev = &a;

    printf("%d %d\n", a.next->data, b.prev->data);

    return 0;
}

Answer

20 10

Step-by-step explanation

A singly linked list has:

data + next

A doubly linked list has:

data + next + prev

So we can travel:

10 → 20
10 ← 20

A circular linked list connects the final node back to the first:

10 → 20 → 30
↑         ↓
└─────────┘

Key takeaway

Doubly linked lists allow movement in both directions; circular lists connect the end back to the beginning.


Module 4 — Stack

Chapter 5 — Stack

A stack follows:

LIFO — Last In, First Out

Question

Predict the output.

#include <stdio.h>

#define SIZE 3

int main(void)
{
    int stack[SIZE];
    int top = -1;

    // Push three values.
    stack[++top] = 10;
    stack[++top] = 20;
    stack[++top] = 30;

    // Pop the most recently inserted value.
    printf("%d\n", stack[top--]);

    // Pop again.
    printf("%d\n", stack[top--]);

    return 0;
}

Answer

30
20

Step-by-step explanation

After pushing:

30  ← top
20
10

The last value inserted is 30.

Therefore:

stack[top--]

returns 30.

Then top decreases.

Next value:

20

This is LIFO.

Real-world examples

Stacks are used for:

  • function calls

  • undo operations

  • expression evaluation

  • parentheses matching

  • DFS

  • backtracking

Key takeaway

Stack = LIFO.


Module 5 — Queue

Chapter 6 — Queue

A queue follows:

FIFO — First In, First Out

Question

Predict the output.

#include <stdio.h>

#define SIZE 3

int main(void)
{
    int queue[SIZE];
    int front = 0;
    int rear = 0;

    // Insert values at the rear.
    queue[rear++] = 10;
    queue[rear++] = 20;
    queue[rear++] = 30;

    // Remove from the front.
    printf("%d\n", queue[front++]);

    // Remove the next item.
    printf("%d\n", queue[front++]);

    return 0;
}

Answer

10
20

Step-by-step explanation

The queue initially contains:

FRONT
  ↓
10  20  30
          ↑
         REAR

The first element inserted is removed first.

That's FIFO.

Key takeaway

Queue = FIFO.


Chapter 6 — Circular Queue

A simple array queue eventually reaches the end of the array even when earlier positions are free.

A circular queue solves this by wrapping around.

Question

What is printed?

#include <stdio.h>

#define SIZE 4

int main(void)
{
    int queue[SIZE];
    int front = 0;
    int rear = 0;

    // Insert three values.
    queue[rear] = 10;
    rear = (rear + 1) % SIZE;

    queue[rear] = 20;
    rear = (rear + 1) % SIZE;

    queue[rear] = 30;
    rear = (rear + 1) % SIZE;

    // Remove one item.
    front = (front + 1) % SIZE;

    // Reuse the freed position.
    queue[rear] = 40;

    printf("%d\n", queue[rear]);

    return 0;
}

Answer

40

Step-by-step explanation

The important expression is:

(rear + 1) % SIZE

When rear reaches the end:

0 → 1 → 2 → 3 → 0 → 1 ...

The % operator creates the circular behavior.

Key takeaway

Circular queues reuse array space by wrapping indexes around.


Module 7 — Hash Tables

Chapter 7 — Hashing

A hash table attempts to provide very fast lookup.

Conceptually:

key
 ↓
hash function
 ↓
index
 ↓
stored value

Question

Predict the output.

#include <stdio.h>

#define SIZE 10

int main(void)
{
    int table[SIZE] = {0};

    // Store 42 using a simple hash.
    int key = 42;
    int index = key % SIZE;

    table[index] = 100;

    // Find the value using the same hash.
    printf("%d\n", table[key % SIZE]);

    return 0;
}

Answer

100

Step-by-step explanation

For:

key = 42

the hash is:

42 % 10 = 2

Therefore:

table[2] = 100

Searching for 42 produces the same index:

42 % 10 = 2

and retrieves:

100

Collision

Different keys can produce the same index:

12 % 10 = 2
42 % 10 = 2

This is called a collision.

Common solutions:

separate chaining
open addressing
linear probing
quadratic probing

Key takeaway

Hash tables trade memory for very fast average-case lookup.


Module 8 — Trees

Chapter 8 — Binary Tree

A binary tree allows each node to have at most two children.

Question

Predict the output.

#include <stdio.h>

struct Node
{
    int data;
    struct Node *left;
    struct Node *right;
};

void preorder(struct Node *root)
{
    if (root == NULL)
        return;

    // Visit the current node.
    printf("%d ", root->data);

    // Visit the left subtree.
    preorder(root->left);

    // Visit the right subtree.
    preorder(root->right);
}

int main(void)
{
    struct Node left = {2, NULL, NULL};
    struct Node right = {3, NULL, NULL};
    struct Node root = {1, &left, &right};

    preorder(&root);

    return 0;
}

Answer

1 2 3

Step-by-step explanation

The tree is:

      1
     / \
    2   3

Preorder means:

ROOT
LEFT
RIGHT

Therefore:

1 → 2 → 3

Tree traversals

Preorder

Root → Left → Right

Inorder

Left → Root → Right

Postorder

Left → Right → Root

Key takeaway

Tree traversal determines the order in which nodes are visited.


Chapter 9 — Binary Search Tree

Question

What does this print?

#include <stdio.h>

struct Node
{
    int data;
    struct Node *left;
    struct Node *right;
};

void inorder(struct Node *root)
{
    if (root == NULL)
        return;

    // Visit smaller values first.
    inorder(root->left);

    printf("%d ", root->data);

    // Visit larger values afterward.
    inorder(root->right);
}

int main(void)
{
    struct Node a = {2, NULL, NULL};
    struct Node b = {8, NULL, NULL};
    struct Node root = {5, &a, &b};

    inorder(&root);

    return 0;
}

Answer

2 5 8

Step-by-step explanation

A Binary Search Tree (BST) follows:

left subtree  < root < right subtree

For:

      5
     / \
    2   8

inorder traversal gives:

2 5 8

This is why inorder traversal of a valid BST produces sorted values.

Key takeaway

BSTs organize values so searching can avoid entire portions of the tree.


Module 9 — Heap & Priority Queue

Chapter 10 — Heap

A heap is commonly represented using an array.

For a zero-based array:

parent(i) = (i - 1) / 2
left(i)   = 2i + 1
right(i)  = 2i + 2

Question

For this array:

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

what is the parent of the element at index 4?

Answer

30

Step-by-step explanation

Index:

i = 4

Parent:

(4 - 1) / 2
= 3 / 2
= 1

Index 1 contains:

30

The tree representation is:

        50
       /  \
     30    40
    /  \
   10  20

A max heap keeps the largest value at the root.

A min heap keeps the smallest value at the root.

Heaps are commonly used to implement:

Priority queues

Key takeaway

Heap = tree-like priority structure commonly stored efficiently in an array.


Module 10 — Graphs

Chapter 11 — Graph Representation

A graph contains:

vertices/nodes
+
edges/connections

Example:

A ─── B
|     |
C ─── D

Question

Predict the output.

#include <stdio.h>

int main(void)
{
    // Adjacency matrix for three vertices.
    int graph[3][3] =
    {
        {0, 1, 1},
        {1, 0, 0},
        {1, 0, 0}
    };

    // Check whether vertex 0 connects to vertex 2.
    printf("%d\n", graph[0][2]);

    return 0;
}

Answer

1

Step-by-step explanation

The matrix means:

      0  1  2
    ----------
0 |   0  1  1
1 |   1  0  0
2 |   1  0  0

Therefore:

graph[0][2]

is 1.

In this representation:

1 = edge exists
0 = edge doesn't exist

Two common graph representations are:

Adjacency matrix

O(V²) memory

Adjacency list

O(V + E) memory

where:

  • V = vertices

  • E = edges

Key takeaway

A graph represents relationships between objects.


Module 11 — Searching

Chapter 12 — Linear Search

Question

What does the function return?

#include <stdio.h>

int linear_search(int numbers[], int size, int target)
{
    // Check every element from left to right.
    for (int i = 0; i < size; i++)
    {
        if (numbers[i] == target)
            return i;
    }

    // Target wasn't found.
    return -1;
}

int main(void)
{
    int numbers[] = {10, 20, 30, 40};

    printf("%d\n", linear_search(numbers, 4, 30));

    return 0;
}

Answer

2

Step-by-step explanation

The function checks:

10 → 20 → 30

30 is at index 2.

Therefore:

return 2

Worst-case complexity:

O(n)

Key takeaway

Linear search checks elements sequentially.


Chapter 13 — Binary Search

Binary search requires sorted data.

Question

Predict the output.

#include <stdio.h>

int binary_search(int a[], int size, int target)
{
    int low = 0;
    int high = size - 1;

    while (low <= high)
    {
        // Find the middle position.
        int mid = low + (high - low) / 2;

        if (a[mid] == target)
            return mid;

        if (a[mid] < target)
            low = mid + 1;
        else
            high = mid - 1;
    }

    return -1;
}

int main(void)
{
    int numbers[] = {10, 20, 30, 40, 50};

    printf("%d\n", binary_search(numbers, 5, 40));

    return 0;
}

Answer

3

Step-by-step explanation

Search:

10 20 30 40 50

Middle:

30

Target:

40

Since:

40 > 30

ignore the left half.

Search:

40 50

Find 40.

Complexity:

O(log n)

Why log n?

Each comparison approximately halves the search space:

1000
 ↓
500
 ↓
250
 ↓
125
 ↓
...

Key takeaway

Binary search is extremely efficient, but the data must be appropriately ordered.


Module 12 — Sorting

Chapter 14 — Bubble Sort

Question

What is the final output?

#include <stdio.h>

int main(void)
{
    int a[] = {3, 1, 2};
    int n = 3;

    // Repeatedly compare neighboring elements.
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = 0; j < n - 1 - i; j++)
        {
            // Swap if elements are in the wrong order.
            if (a[j] > a[j + 1])
            {
                int temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }

    printf("%d %d %d\n", a[0], a[1], a[2]);

    return 0;
}

Answer

1 2 3

Step-by-step explanation

Bubble sort repeatedly compares neighbors.

Initially:

3 1 2

First pass:

3 1 → swap → 1 3 2
3 2 → swap → 1 2 3

Sorted.

Worst-case:

O(n²)

Key takeaway

Bubble sort is simple but inefficient for large datasets.


Chapter 15 — Selection Sort

Selection sort repeatedly finds the smallest remaining element.

Conceptually:

[5, 2, 4, 1]

find smallest → 1
put it first

[1, 2, 4, 5]

Then continue with the remaining portion.

Complexity:

Best:    O(n²)
Average: O(n²)
Worst:   O(n²)

Its advantage is that it performs relatively few swaps.

Key takeaway

Selection sort repeatedly selects the next smallest element.


Chapter 16 — Insertion Sort

Insertion sort builds the sorted portion one element at a time.

Question

What is the final output?

#include <stdio.h>

int main(void)
{
    int a[] = {3, 1, 2};
    int n = 3;

    for (int i = 1; i < n; i++)
    {
        // Save the element being inserted.
        int key = a[i];

        int j = i - 1;

        // Shift larger values to the right.
        while (j >= 0 && a[j] > key)
        {
            a[j + 1] = a[j];
            j--;
        }

        // Put key into its correct position.
        a[j + 1] = key;
    }

    printf("%d %d %d\n", a[0], a[1], a[2]);

    return 0;
}

Answer

1 2 3

Step-by-step explanation

Think of sorting playing cards.

You already have:

3

Insert 1:

1 3

Insert 2:

1 2 3

Worst-case:

O(n²)

But for nearly sorted data, insertion sort can perform very well.

Key takeaway

Insertion sort is particularly useful for small or nearly sorted datasets.


Module 13 — Divide and Conquer

Chapter 17 — Merge Sort

Merge sort follows:

Divide
↓
Sort smaller pieces
↓
Merge

Example:

[8 3 2 9]

      divide
       ↓
[8 3] [2 9]

  ↓       ↓

[3 8] [2 9]

       merge

[2 3 8 9]

Complexity

Best:    O(n log n)
Average: O(n log n)
Worst:   O(n log n)

Typical additional space:

O(n)

Key takeaway

Merge sort repeatedly divides the problem and efficiently merges sorted pieces.


Chapter 18 — Quicksort

Quicksort chooses a pivot.

Then it partitions elements around that pivot.

Conceptually:

[7 2 9 4 1]

pivot = 4

smaller: [2 1]
pivot:   [4]
larger:  [7 9]

Then recursively sort the two sides.

Average complexity:

O(n log n)

Worst case:

O(n²)

The quality of pivot selection matters greatly.

Key takeaway

Quicksort partitions around a pivot and recursively sorts the partitions.


Chapter 19 — Heap Sort

Heap sort uses a heap.

For ascending order, a max heap can repeatedly move the largest element to the end.

Complexity:

Best:    O(n log n)
Average: O(n log n)
Worst:   O(n log n)

It has an important theoretical advantage:

Worst-case O(n log n) without requiring an auxiliary array like merge sort.

Key takeaway

Heap sort combines heap operations with sorting.


Module 14 — Recursion

Chapter 20 — Recursion

A recursive function calls itself.

Question

Predict the output.

#include <stdio.h>

void countdown(int n)
{
    // Stop the recursion.
    if (n == 0)
        return;

    printf("%d ", n);

    // Call the function with a smaller problem.
    countdown(n - 1);
}

int main(void)
{
    countdown(3);

    return 0;
}

Answer

3 2 1

Step-by-step explanation

countdown(3)
    ↓
countdown(2)
    ↓
countdown(1)
    ↓
countdown(0)
    ↓
return

Every recursive function needs a base case.

Without:

if (n == 0)
    return;

the function could recurse indefinitely and eventually exhaust the call stack.

Key takeaway

Recursion = solving a problem by solving smaller versions of the same problem.


Module 15 — Complexity

Chapter 21 — Big O

Big O describes how an algorithm's resource requirements grow as input size increases.

Core complexities

ComplexityGeneral idea
O(1)Constant
O(log n)Repeatedly divide problem
O(n)Process each element
O(n log n)Efficient divide-and-conquer
O(n²)Nested comparison pattern
O(2ⁿ)Explosive growth
O(n!)Extremely explosive growth

Question

What is the complexity?

for (int i = 0; i < n; i++)
{
    printf("%d\n", i);
}

Answer

O(n)

Because the loop executes approximately n times.


Another question

What is the complexity?

for (int i = 0; i < n; i++)
{
    for (int j = 0; j < n; j++)
    {
        printf("%d %d\n", i, j);
    }
}

Answer

O(n²)

The outer loop runs n times.

For every outer iteration, the inner loop runs n times:

n × n = n²

Important distinction

Big O isn't simply:

“How many milliseconds does this program take?”

It describes growth as the input becomes larger.

Key takeaway

Big O helps you predict how an algorithm scales.


Module 16 — Space Complexity

Chapter 22 — Time vs Space

An algorithm can consume resources in two major ways:

Time → computation
Space → additional memory

Example:

int copy_array(int source[], int destination[], int n)
{
    for (int i = 0; i < n; i++)
        destination[i] = source[i];

    return 0;
}

The operation requires:

Time:  O(n)

The caller already provided the destination array, so the function itself doesn't allocate another n-element structure.

Contrast that with an algorithm that allocates:

int *copy = malloc(n * sizeof(int));

Now additional memory proportional to n is used.

Key takeaway

Algorithm analysis considers both computation and memory usage.


Module 17 — Greedy Algorithms

Chapter 23 — Greedy Thinking

A greedy algorithm repeatedly chooses what looks best right now.

Classic examples include:

  • activity selection

  • fractional knapsack

  • some scheduling problems

  • Huffman coding

  • minimum spanning tree algorithms

But greedy is dangerous if the local best choice doesn't lead to the global best answer.

Example

Suppose you have:

Coins: 25, 10, 5, 1
Amount: 41

Greedy chooses:

25
10
5
1

giving:

4 coins

But not every coin system behaves this nicely.

Key takeaway

Greedy algorithms make locally optimal choices; you must prove that those choices lead to a globally optimal solution.


Module 18 — Dynamic Programming

Chapter 24 — DP Basics

Dynamic programming is useful when a problem contains:

  1. Overlapping subproblems

  2. Optimal substructure

A classic example is Fibonacci.

Naive recursion repeatedly solves the same problems:

fib(5)
├── fib(4)
│   ├── fib(3)
│   └── fib(2)
└── fib(3)
    ├── fib(2)
    └── fib(1)

fib(3), fib(2), etc. are calculated repeatedly.

DP stores previous answers.

Question

What does this print?

#include <stdio.h>

int main(void)
{
    int n = 6;
    int dp[7];

    dp[0] = 0;
    dp[1] = 1;

    // Build answers from smaller answers.
    for (int i = 2; i <= n; i++)
        dp[i] = dp[i - 1] + dp[i - 2];

    printf("%d\n", dp[n]);

    return 0;
}

Answer

8

Step-by-step explanation

The table becomes:

index:  0 1 2 3 4 5 6
value:  0 1 1 2 3 5 8

Instead of repeatedly recomputing values, we save them.

This is called memoization/tabulation, depending on the approach.

Key takeaway

Dynamic programming avoids repeated work by remembering previously solved subproblems.


Module 19 — Tree Algorithms

Chapter 25 — Tree Traversal

The three fundamental depth-first traversals are:

Preorder:
Root → Left → Right

Inorder:
Left → Root → Right

Postorder:
Left → Right → Root

For:

      A
     / \
    B   C

we get:

Preorder  = A B C
Inorder   = B A C
Postorder = B C A

For a BST, inorder traversal is particularly important because it produces sorted order.

Key takeaway

Traversal algorithms define systematic ways to visit every tree node.


Module 20 — Graph Algorithms

Chapter 26 — BFS and DFS

Two fundamental graph traversal techniques are:

BFS — Breadth-First Search

Uses a queue.

It explores:

level by level

DFS — Depth-First Search

Uses:

recursion / stack

It explores deeply before backtracking.

Consider:

A
├── B
│   ├── D
│   └── E
└── C

Possible DFS order:

A B D E C

Possible BFS order:

A B C D E

Important applications

BFS:

  • shortest path in an unweighted graph

  • level-order traversal

DFS:

  • cycle detection

  • connected components

  • topological sorting

  • maze/backtracking problems

Key takeaway

BFS thinks in levels; DFS thinks in depth.


Module 21 — Important Graph Algorithms

Chapter 27 — Shortest Paths & Connectivity

Important algorithms to know:

BFS

Shortest path in an unweighted graph.

Dijkstra

Shortest paths when edge weights are non-negative.

Bellman-Ford

Handles negative edge weights and can detect negative cycles.

Floyd-Warshall

All-pairs shortest paths.

Typical complexity:

O(V³)

Minimum Spanning Tree

Two famous algorithms:

Kruskal

sort edges
→ repeatedly select cheapest valid edge

Prim

start with a vertex
→ repeatedly add cheapest connecting edge

Key takeaway

Graph algorithms solve problems involving paths, connectivity, dependencies and networks.


Final Phase 7 Cheat Sheet

You should now have this mental map:

                    DATA STRUCTURES
                          │
       ┌──────────────────┼──────────────────┐
       │                  │                  │
     Linear            Hashing             Trees
       │                  │                  │
 ┌─────┼─────┐            │           ┌──────┼──────┐
Array List  Stack        Hash       Binary   BST    Heap
       │      │
     Queue
       │
 Circular

And:

                    ALGORITHMS
                        │
        ┌───────────────┼────────────────┐
        │               │                │
     Search           Sort            Traversal
        │               │                │
   Linear/Binary   Bubble/Selection   BFS / DFS
                   Insertion
                   Merge
                   Quick
                   Heap

Then the higher-level thinking:

Algorithmic Thinking
        │
        ├── Recursion
        ├── Big O
        ├── Space Complexity
        ├── Divide & Conquer
        ├── Greedy
        └── Dynamic Programming

The complexity table you should memorize

Algorithm / StructureTypical complexity
Array accessO(1)
Linear searchO(n)
Binary searchO(log n)
Linked-list traversalO(n)
Stack push/popO(1)
Queue enqueue/dequeueO(1)
Hash-table lookupO(1) average
BST searchO(log n) average
BST searchO(n) worst case
Heap insertO(log n)
Heap removeO(log n)
Bubble sortO(n²)
Selection sortO(n²)
Insertion sortO(n²) worst
Merge sortO(n log n)
QuicksortO(n log n) average
QuicksortO(n²) worst
Heap sortO(n log n)
BFSO(V + E)
DFSO(V + E)
Floyd-WarshallO(V³)

Phase 7 mastery target

You should be able to look at a problem and ask:

What data am I storing?

→ Choose a data structure.

Then:

What operation matters most?

→ Optimize the structure around that operation.

Then:

How will I solve the problem?

→ Choose an algorithm.

Then:

How does it scale?

→ Analyze time + space complexity.

That is the core of Data Structures & Algorithms in C.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.