Data Structures, Algorithms, and Analysis: Complete Study Notes
Data Structures Foundations and Classification
Data Definition: A collection of raw facts.
Data Structure: A specialized format for organizing, storing, and representing logical relationships existing between individual data elements in computer memory.
Key Characteristics of Data Structures:
Logical representation of data in computer memory.
Logical relationships defined between various data elements.
Facilitates efficient manipulation and processing of stored data elements.
Need for Data Structures
Modern applications process growing volumes of data, introducing key computational challenges:
Processor Speed Limits: High-speed processing is required for massive datasets. As datasets scale to billions of records per entity, processor execution speeds hit physical limits if data is unorganized.
Data Search Scalability: Searching through an unindexed inventory of items sequentially requires up to comparisons per query, causing severe application slowdowns.
Simultaneous Requests: High-traffic web servers processing thousands of concurrent user queries can fail without structured data organization.
Advantages of Data Structures
Efficiency: Choosing an optimal data structure drastically reduces execution time (e.g., using ordered arrays, binary search trees, or hash tables instead of linear arrays for lookup operations).
Reusability: Once implemented, data structure modules can be compiled into libraries and reused across different client applications.
Abstraction: Data structures implement Abstract Data Types (ADTs), providing a clean interface to client code while hiding implementation details.
Data Structures Classification

Primitive Data Structures: Predefined data types built directly into the programming language (e.g.,
int,char,float,double).Non-Primitive Data Structures: Complex data structures constructed from primitive data types:
Linear Data Structures: Data elements arranged sequentially where each element is connected to its previous and next adjacent elements (e.g., Array, Stack, Queue, Linked List).
Non-Linear Data Structures: Data elements organized hierarchically or in interconnected networks (e.g., Trees, Graphs).
Basic Data Structure Operations
Traversing: Accessing each data element exactly once to process or display it.
Searching: Finding the memory location of an element matching a given key value.
Insertion: Adding a new data element into the structure.
Deletion: Removing an existing data element from the structure.
Sorting: Arranging data elements in a specific numerical or lexicographical order.
Merging: Combining elements from two different structures into a single structure.
Linear Data Structures: Arrays
Array Characteristics and Types
Definition: An array is a linear collection of fixed number of homogeneous data elements stored at contiguous memory locations under a single variable name.
Key Characteristics:
Elements are referenced using a single array name and distinguished by index values.
Indexing starts at in C language.
Array name serves as a pointer to the first element (base address).
Array size must be a constant expression determined at compile-time.
Memory is allocated contiguously at runtime; no automatic boundary checking is performed by low-level languages like C.
Array Types:
One-dimensional Array (
array[]): A linear group of homogeneous elements (e.g.,{2, 5, 6, 1, 9}).Multi-dimensional Array (
array[][].[]): An array of arrays where each element is itself an array (e.g., a matrix or group of strings like{"Ajay", "Vikas", "Amit", "Sumit"}).
Memory Representation and Addressing Calculations

One-Dimensional Array Addressing Formula
Given an array with base address , word size (element memory size) , index , and lower bound (default ):
Worked Examples:
For an array arr[5] = {2, 6, 7, 3, 8} with base address and word size :
Address of
arr[2]:Address of
arr[4]:
Multi-Dimensional Array Memory Layout

Two-dimensional arrays are stored linearly in memory using two mapping strategies:
Row-Major Order: Elements are stored row by row sequentially.
Column-Major Order: Elements are stored column by column sequentially.
Address Computation Formulas for 2D Array :
Row-Major Order:
Column-Major Order:
Where:
= Base Address
= Word size (bytes per element)
= Total number of rows
= Total number of columns
= Target row and column indices
= Lower bound of row index
= Lower bound of column index
Comprehensive Worked Example:
Given a matrix implemented as A[10][12] with base address , word size , and lower bounds ():
Compute Address of :
Row-Major Order:
Column-Major Order:
Compute Address of :
Row-Major Order:
Column-Major Order:
Array Algorithms and C Implementations
Array Traversal
Algorithm TRAVERSE(LA, LB, UB):
Set
Repeat Steps 3 and 4 while
Apply
PROCESStoSet
Exit
#include <stdio.h>
#include <conio.h>
void traverse(int *array, int size) {
int i;
for(i = 0; i < size; i++) {
printf("arr[%d] = %d\n", i, array[i]);
}
}
void main() {
int arr[5] = {2, 6, 7, 3, 8};
int N = 5;
clrscr();
printf("Press any key to perform array traversal and display its elements: \n\n");
getch();
traverse(arr, N);
getch();
}
Array Insertion
Algorithm INSERT(LA, N, K, ITEM):
Set
Repeat Steps 3 and 4 while
Set (Shift element downward)
Set
Set
Set
Exit
Array Deletion
Algorithm DELETE(LA, N, K, ITEM):
Set
Repeat for to :
Set (Shift element upward)
Set
Exit
Linear Search
Linear search scans elements sequentially from index to . A sentinel can be placed at to streamline loop condition testing.
Algorithm LINEAR(DATA, N, ITEM, LOC):
Set (Insert sentinel)
Set
Repeat while :
Set
If , then Set (Search unsuccessful)
Exit
Time Complexity: Worst-case , Best-case , Average-case comparisons.
Binary Search
Binary Search operates on a sorted array by halving the search space recursively or iteratively.
Prerequisites:
Array must be in sorted order.
Direct indexing/random access must take time.
Algorithm BINARY(DATA, LB, UB, ITEM, LOC):
Set
Repeat Steps 3 and 4 while and
If , then Set ; Else Set
Set
If , then Set ; Else Set
Exit
Limitations of Binary Search:
Dataset must be strictly sorted; initial sorting costs .
Maintaining sorted order during frequent insertions and deletions is costly ( shifting).
Inefficient for pointer-based Linked Lists because finding the middle element takes time.
Bubble Sort
Bubble sort repeatedly compares adjacent elements and swaps them if they are out of order, bubbling the largest unsorted element to its correct end position in each pass.
Algorithm BUBBLE(DATA, N):
Repeat Steps 2 and 3 for to
Set
Repeat while
If , then Swap and
Set
Exit
Bubble Sort Complexity Derivation: Number of comparisons across passes:
Stacks
Definition and Abstract Data Type Properties
Definition: A stack is a linear data structure operating on the Last-In-First-Out (LIFO) principle. All insertions (
push) and deletions (pop) occur restrictedly at a single designated end calledtop.Real-World Examples: Stack of books, stack of clothes, stack of plates.
Array vs. Stack Comparison
Property | Array | Stack |
|---|---|---|
Structure | Collection identified by numerical indices starting at . | ADT operating strictly on LIFO principle. |
Data Types | Homogeneous data elements. | Elements of defined type managed via top. |
Access Pattern | Random access to any element at any index. | Restricted access; only |
Operations | Rich set: traversing, searching, insertion, deletion, sorting. | Limited set: |
Use Cases | Inventory management, fixed list grouping. | System tasks, recursion management, function call stack. |
Stack Operations and Memory Representation

Memory Allocation: Contiguous array block managed via pointer
TOP.Operations:
Push: Increments
TOPby and stores new element atSTACK[TOP]. Check forTOP == MAXSTK(OVERFLOW).Pop: Retrieves element at
STACK[TOP]and decrementsTOPby . Check forTOP == 0orNULL(UNDERFLOW).
Stack Algorithms
Algorithm PUSH(STACK, TOP, MAXSTK, ITEM):
If , then Print "OVERFLOW", and Return
Set
Set
Return
Algorithm POP(STACK, TOP, ITEM):
If , then Print "UNDERFLOW", and Return
Set
Set
Return
Applications of Stacks
String Reversal (Pushing chars sequentially, then popping into target string)
Undo/Redo mechanisms in text editors
Subroutine call stack and Recursion execution
Graph traversal algorithms (Depth First Search / DFS)
Expression evaluation and parsing
Arithmetic Expressions and Polish Notation
Infix expressions like depend on operator precedence and parentheses. Polish notations eliminate parentheses ambiguity.
Infix Notation: Operator between operands ().
Prefix (Polish) Notation: Operator precedes operands ().
Postfix (Reverse Polish) Notation: Operator follows operands ().
Operator Precedence Hierarchy
Highest: Exponentiation (
^)Next Highest: Multiplication (
*) and Division (/)Lowest: Addition (
+) and Subtraction (-)
Infix, Prefix, and Postfix Equivalence Table
Infix | Prefix (Polish) | Postfix (Reverse Polish) |
|---|---|---|
Evaluation of Postfix Expression Algorithm
To evaluate postfix expression :
Append sentinel ")" to end of
Scan left to right until ")" is encountered
If an operand is scanned, push onto
STACKIf an operator is scanned:
Pop top element and next-to-top element
Evaluate result
Push result back onto
STACK
Set
VALUEequal to top element ofSTACKand exit
Worked Evaluation Example:
Evaluate Postfix representation: 5, 6, 2, +, *, 12, 4, /, -
Symbol Scanned | STACK State | Operation Performed / Explanation |
|---|---|---|
|
| Push operand |
|
| Push operand |
|
| Push operand |
|
| Pop and ; evaluate ; push |
|
| Pop and ; evaluate ; push |
|
| Push operand |
|
| Push operand |
|
| Pop and ; evaluate ; push |
|
| Pop and ; evaluate ; push |
|
| Sentinel reached; final result = |
Transforming Infix to Postfix Algorithm (POLISH(Q, P))
Push
(ontoSTACKand append)to end of infix expressionScan left-to-right until
STACKis empty:If operand: add to postfix string
If
(: push ontoSTACKIf operator : repeatedly pop operators from
STACKwith same or higher precedence than and add to ; then push ontoSTACKIf
): repeatedly pop fromSTACKto until(is popped; discard(
Detailed Transformation Step Trace:
Infix: Output Postfix : A B C * D E F ^ / G * - H * +
Queues
Definition and Core Concepts
Definition: A Queue is a linear data structure operating on the First-In-First-Out (FIFO) principle. Elements enter at the
Rearend and leave from theFrontend.

Applications: CPU scheduling, shared printer queues in computer networks, memory buffer management.
Standard Queue Operations
Insert (Enqueue): Receives item, increments
rearpointer, stores item at newrearlocation.Delete (Dequeue): Retrieves front item, increments
frontpointer to point to next element.
Circular Queues
Linear array implementations waste space when elements are deleted because front shifts right, leaving unused memory at lower indices. A Circular Queue connects start (index 0) to end (index N-1) logically.

Circular Queue Algorithms
Procedure QINSERT(QUEUE, N, FRONT, REAR, ITEM):
If OR , then Write "OVERFLOW", Return
If , then Set Else if , then Set Else Set
Set
Return
Procedure QDELETE(QUEUE, N, FRONT, REAR, ITEM):
If , then Write "UNDERFLOW", Return
Set
If , then Set (Queue empty) Else if , then Set Else Set
Return
Priority Queues
Definition: A queue variant where each element carries an assigned priority. Elements are dequeued based on priority rather than arrival time.
Rules:
Higher priority elements are deleted before lower priority elements.
Equal priority elements are processed on a First-In-First-Out (FIFO) basis.
Implementation Options:
Unsorted insertion + search for highest priority element during deletion.
Sorted insertion (elements inserted into sorted position by priority) + sequential deletion from front.
Double-Ended Queue (Deque)
Definition: A linear structure where insertions and deletions can occur at both ends (
FrontandRear), but not in the middle.Deque Categories:
Input-Restricted Deque: Deletion permitted at both ends; insertion restricted to one end.
Output-Restricted Deque: Insertion permitted at both ends; deletion restricted to one end.
Four Basic Operations:
InsertFront(x),InsertRear(x),DeleteFront(),DeleteRear().
Deque Algorithms
InsertFront(x):
If , Output "OVERFLOW"
Else if , Set
Else if , Set
Else Set
Set
InsertRear(x):
If , Output "OVERFLOW"
Else if , Set
Else if , Set
Else Set
Set
DeleteFront():
If , Output "UNDERFLOW"
Set
If , Set
Else if , Set
Else Set
Return
DeleteRear():
If , Output "UNDERFLOW"
Set
If , Set
Else if , Set
Else Set
Return
Singly Linked Lists
Concept and Node Architecture
Arrays allocate memory contiguously at compile time, leading to memory space wastage if fewer elements are inserted. Linked lists allocate memory dynamically at runtime node-by-node.

Node Anatomy: Each node contains:
INFO: Data payload field.NEXT: Pointer containing memory address of successor node.
Head Pointer (
FIRST/START): Points to first node in list; set toNULLwhen list is empty.Tail Node:
NEXTfield of final node containsNULLsentinel.
C Structures and Self-Referential Declarations
To store multi-attribute data structures (e.g. Student record with roll number, name, marks):
struct student {
int rno; /* 4 bytes */
char name[10]; /* 10 bytes */
float marks; /* 4 bytes */
};
/* Total sizeof(struct student) = 18 bytes */
A linked list node declaration uses a self-referential structure (contains a pointer to its own structure type):
struct node {
int INFO;
struct node *NEXT;
};
Comparison: Array vs. Linked List
Characteristic | Array | Linked List |
|---|---|---|
Memory Allocation | Static memory allocation (compile time). | Dynamic memory allocation (runtime). |
Memory Layout | Contiguous memory locations. | Non-contiguous memory locations connected via pointers. |
Insertion / Deletion | Expensive () due to element shifting. | Efficient () at known pointer positions. |
Access Time | direct random access via index. | sequential access starting from head. |
Memory Overhead | Fixed size overhead; potential unused space. | Extra memory per element for |
Singly Linked List Operations
Traversal C Functions
/* In-order traversal */
void traverseinorder(struct node *head) {
while(head != NULL) {
printf("%d\n", head->INFO);
head = head->NEXT;
}
}
/* Reverse order traversal using recursion */
void traversereverseorder(struct node *head) {
if(head->NEXT != NULL) {
traversereverseorder(head->NEXT);
}
printf("%d\n", head->INFO);
}
Searching Functions
/* Search Unsorted Linked List */
struct node* searchunsortedlist(struct node *head, int item) {
while((head != NULL) && (head->INFO != item)) {
head = head->NEXT;
}
return head;
}
/* Search Sorted Linked List (Ascending) */
struct node* searchinsortedlist(struct node *head, int item) {
while(head != NULL) {
if(head->INFO == item) return head;
else if(item < head->INFO) return NULL;
else head = head->NEXT;
}
return NULL;
}
Insertion Functions
/* Insert at Beginning */
void insertatbegining(struct node **head, int item) {
struct node *ptr = (struct node*)malloc(sizeof(struct node));
ptr->INFO = item;
if(*head == NULL) ptr->NEXT = NULL;
else ptr->NEXT = *head;
*head = ptr;
}
/* Insert at End */
void insertatend(struct node **head, int item) {
struct node *ptr, *loc;
ptr = (struct node*)malloc(sizeof(struct node));
ptr->INFO = item;
ptr->NEXT = NULL;
if(*head == NULL) {
*head = ptr;
} else {
loc = *head;
while(loc->NEXT != NULL) loc = loc->NEXT;
loc->NEXT = ptr;
}
}
/* Insert After Given Element */
void insertafterelement(struct node *head, int item, int after) {
struct node *ptr, *loc;
loc = searchunsortedlist(head, after);
if(loc == NULL) return;
ptr = (struct node*)malloc(sizeof(struct node));
ptr->INFO = item;
ptr->NEXT = loc->NEXT;
loc->NEXT = ptr;
}
Deletion Functions
/* Delete from Beginning */
void deletefrombegining(struct node **head) {
struct node *ptr;
if(*head == NULL) return;
ptr = *head;
*head = (*head)->NEXT;
free(ptr);
}
/* Delete from End */
void deletefromend(struct node **head) {
struct node *ptr, *loc;
if(*head == NULL) return;
if((*head)->NEXT == NULL) {
ptr = *head;
*head = NULL;
free(ptr);
} else {
loc = *head;
ptr = (*head)->NEXT;
while(ptr->NEXT != NULL) {
loc = ptr;
ptr = ptr->NEXT;
}
loc->NEXT = NULL;
free(ptr);
}
}
/* Delete Entire List */
void deletelist(struct node **head) {
struct node *ptr;
while(*head != NULL) {
ptr = *head;
*head = (*head)->NEXT;
free(ptr);
}
}
Recursion and Divide-and-Conquer
Divide-and-Conquer Methodology
Strategy: Divides a complex problem into smaller independent subproblems, solves each subproblem either directly or recursively, and recombines partial solutions into a global solution.
Core Principle: "If the problem is too difficult to solve when it is first presented, simplify it and try again."
Mechanics of Recursion
Definition: The mechanism where a function calls itself directly or indirectly.
Essential Properties:
Base Case: One or more simple terminating conditions that return a direct non-recursive answer.
Recursive Step / General Case: Problem is redefined in terms of smaller input sizes approaching the base case.
Infinite Recursion Warning: Every call must strictly reduce task size; failure to reach a base case causes call stack overflow.

Direct Recursion: Function explicitly invokes .
Indirect Recursion: Function calls , and subsequently calls .
Iteration vs. Recursion
Property | Iteration | Recursion |
|---|---|---|
Repetition Mechanism | Uses explicit control loops ( | Uses repeated self-function calls. |
Termination | Loop condition evaluates to false. | Base case condition is recognized. |
Memory Overhead | Requires minimal stack space (). | Requires memory overhead for call stack frames (). |
Performance | Typically faster execution. | Overhead of repeated function calls. |
Design Balance | Preferred for speed and resource limits. | Preferred for clear, elegant algorithm design. |
Recursion Examples
Sum of First Positive Integers
/* Recursive sum implementation */
int sum(int n) {
if (n <= 1) return n; /* Base case */
else return (n + sum(n - 1)); /* General recursive step */
}
Trace for sum(5):
Factorial Function ()
Mathematical definition: where .
#include <stdio.h>
long factorial(long number) {
if (number <= 1) return 1; /* Base case */
else return (number * factorial(number - 1)); /* Recursive step */
}
int main() {
int i;
for (i = 1; i <= 10; i++) {
printf("%2d! = %ld\n", i, factorial(i));
}
return 0;
}
Fibonacci Series
Definition: where .
long fibonacci(long n) {
if (n == 0 || n == 1) return n; /* Base case */
else return fibonacci(n - 1) + fibonacci(n - 2); /* Double recursion */
}
Complexity: Time complexity is exponential due to redundant sub-tree recalculations.
Towers of Hanoi

Puzzle Rules: Move disks from peg
BEGto pegENDusing auxiliary pegAUX.Move only 1 disk at a time.
Only top disk can be moved.
No larger disk may be placed on a smaller disk.
Algorithm TOWER(N, BEG, AUX, END):
If , then:
Write:
Return
Call
TOWER(N - 1, BEG, END, AUX)Write:
Call
TOWER(N - 1, AUX, BEG, END)Return
Algorithm Analysis and Asymptotic Notations
Principles of Asymptotic Analysis
Asymptotic analysis measures algorithm efficiency as input size , evaluating runtime or space requirements independently of hardware, compiler, or programming language.
Types of Analysis
Worst-Case Analysis (Upper Bound): Calculates maximum execution operations for input of size . (Standard benchmark; e.g. linear search when item is absent requires comparisons).
Best-Case Analysis (Lower Bound): Calculates minimum operations required. (e.g. linear search when item is at index requires comparisons).
Average-Case Analysis: Calculates expected computing time across all uniformly distributed input cases.
Asymptotic Notations
Big-O Notation (Upper Bound / Worst Case)
if there exist positive constants and such that:
Mathematical Proof Example:
Prove .
Condition:
Let and :
For : (True)
For : (True)
Thus, .
Big-Omega Notation (Lower Bound / Best Case)
if there exist positive constants and such that:
Mathematical Proof Example:
Prove .
Condition:
Choose :
Big-Theta Notation (Tight Bound / Average Case)
if there exist positive constants , and such that:
Mathematical Proof Example:
Prove .
Condition:
Let :
Rate of Growth Comparison

Standard complexity ordering:
Function Values Growth Comparison Table
Input Size | ||||||
|---|---|---|---|---|---|---|
5 | ||||||
10 | ||||||
100 | ||||||
1000 |
Common Time Complexities Summary
Complexity | Example Algorithm | Growth Behavior |
|---|---|---|
Array index lookup | Constant time | |
Binary Search | Logarithmic; extremely slow growth | |
Linear Search | Linear growth | |
Merge Sort, Quick Sort (Avg) | Efficient sorting complexity | |
Bubble Sort, Insertion Sort | Quadratic growth | |
Recursive Fibonacci | Exponential; impractical for large inputs |