EXAMhelp
DailyPracticeNotesMocksLogin

Notes / GATE / 06

Data Structures

6 chapters · GATE revision notes

EXAMhelp · GATE notes

Data Structures

CH 01Array

What is an array?Array kya hota hai?

An array stores elements of the same type in one contiguous block of memory. Because every element has the same size, the address of any element can be computed directly from its index, which is why access by index takes O(1) time.Array same type ke elements ko memory ke ek hi continuous block mein store karta hai. Har element ka size same hota hai, isliye kisi bhi index ka address seedha calculate ho jaata hai — isi wajah se index se access O(1) time mein hota hai.

Operations and their costOperations aur unki cost

OperationTimeWhy
Access a[i]O(1)Address = base + i × size
Search (unsorted)O(n)Linear scan
Search (sorted)O(log n)Binary search
Insert / delete at endO(1)No shifting (if space is available)
Insert / delete at position iO(n)Elements after i must shift

Address calculation (1-D)Address calculation (1-D)

For an array A[lb … ub] with base address B and element size w bytes:Array A[lb … ub] ke liye, jiska base address B hai aur har element w bytes ka hai:

Address(A[i]) = B + (i − lb) × w

TipExample: A[−5 … 5] of 4-byte ints at base 1000. Address of A[2] = 1000 + (2 − (−5)) × 4 = 1028.Example: A[−5 … 5] of 4-byte ints, base 1000. A[2] ka address = 1000 + (2 − (−5)) × 4 = 1028.

Address calculation (2-D)Address calculation (2-D)

For A[lr … ur][lc … uc] with m rows and n columns, the array is laid out either row by row or column by column.A[lr … ur][lc … uc] mein m rows aur n columns hain. Array ya toh row-by-row store hota hai ya column-by-column.

OrderUsed byAddress of A[i][j]
Row-majorC, C++, JavaB + ((i − lr) × n + (j − lc)) × w
Column-majorFortran, MATLABB + ((j − lc) × m + (i − lr)) × w

Common mistakeCommon galtiRow-major multiplies by the number of columns (n); column-major multiplies by the number of rows (m). Mixing these up is the most common GATE mistake here.Row-major mein number of columns (n) se multiply karte hain; column-major mein number of rows (m) se. Inko mix karna GATE ki sabse common galti hai.

Special matricesSpecial matrices

  • Lower-triangular n × n matrix stores n(n + 1)/2 non-zero elements.
  • Row-major index of A[i][j] (i ≥ j, 1-indexed) in a lower-triangular store: i(i − 1)/2 + (j − 1).
  • Tridiagonal matrix has 3n − 2 non-zero elements.
  • Sparse matrices are stored as (row, col, value) triplets to save space.
  • Lower-triangular n × n matrix mein n(n + 1)/2 non-zero elements store hote hain.
  • Lower-triangular store mein A[i][j] (i ≥ j, 1-indexed) ka row-major index: i(i − 1)/2 + (j − 1).
  • Tridiagonal matrix mein 3n − 2 non-zero elements hote hain.
  • Sparse matrix ko space bachane ke liye (row, col, value) triplets mein store karte hain.

Arrays in CC mein arrays

int a[5] = {1, 2, 3, 4, 5};
int *p = a;          // array name decays to &a[0]
printf("%d", *(p + 2));   // 3, same as a[2]
printf("%d", 2[a]);       // also 3: a[i] == *(a + i) == i[a]
sizeof(a);                // 20 (5 × 4) — the whole array
sizeof(p);                // size of a pointer (e.g. 8)

Common mistakeCommon galtiInside a function, an array parameter is just a pointer, so sizeof gives the pointer size, not the array size.Function ke andar array parameter sirf ek pointer hota hai, isliye sizeof pointer ka size deta hai, array ka nahi.

Quick revision

  • Elements sit in contiguous memory, so a[i] is O(1) random access.
  • Insert/delete in the middle is O(n) because elements must shift.
  • Row-major (C): A[i][j] is stored after i full rows of n columns each.
  • Column-major (Fortran): A[i][j] is stored after j full columns of m rows each.

Formulas & facts

1-D address
Base + (i − lb) × size
2-D row-major (m × n)
Base + ((i − lr) × n + (j − lc)) × size
2-D column-major (m × n)
Base + ((j − lc) × m + (i − lr)) × size
Lower-triangular elements
n(n + 1) / 2

CH 02Stack

What is a stack?Stack kya hota hai?

A stack is a LIFO (last in, first out) list: elements are added and removed only at one end, called the top. Think of a pile of plates.Stack ek LIFO (last in, first out) list hai: elements sirf ek hi end se add aur remove hote hain, jise top kehte hain. Plates ke dher ki tarah socho — jo plate sabse upar rakhi, wahi sabse pehle uthegi.

OperationsOperations

OperationTimeNotes
push(x)O(1)Overflow if the array is full
pop()O(1)Underflow if the stack is empty
peek() / top()O(1)Read without removing
isEmpty()O(1)top == −1 in the array version
#define MAX 100
int st[MAX], top = -1;

void push(int x) { if (top == MAX - 1) return; /* overflow */ st[++top] = x; }
int  pop(void)   { if (top == -1) return -1;   /* underflow */ return st[top--]; }

ApplicationsApplications

  • Function calls and recursion (call stack / activation records).
  • Expression conversion (infix → postfix/prefix) and evaluation.
  • Balanced-parentheses checking.
  • Undo/redo, browser back button, DFS.
  • Function calls aur recursion (call stack / activation records).
  • Expression conversion (infix → postfix/prefix) aur evaluation.
  • Balanced parentheses check karna.
  • Undo/redo, browser ka back button, DFS.

Infix to postfixInfix se postfix

  • Operand → write it to the output.
  • '(' → push.
  • ')' → pop to output until '(' is popped (discard both brackets).
  • Operator → pop operators with higher precedence (or equal precedence if left-associative) to output, then push it.
  • End → pop everything left.
  • ^ is right-associative, so an incoming ^ does not pop another ^.
  • Operand → seedha output mein likh do.
  • '(' → push karo.
  • ')' → '(' milne tak sab pop karke output mein daalo (dono brackets discard).
  • Operator → jo operators higher precedence ke hain (ya equal, agar left-associative hai) unhe pop karke output mein daalo, phir isko push karo.
  • End → jo bacha hai sab pop kar do.
  • ^ right-associative hai, isliye naya ^ purane ^ ko pop nahi karta.
SymbolStackOutput
aa
++a
b+a b
*+ *a b
c+ *a b c
enda b c * +

Tipa + b * c → a b c * +. Precedence: ^ > * / > + −.a + b * c → a b c * +. Precedence: ^ > * / > + −.

Postfix evaluationPostfix evaluation

Scan left to right. Push operands. On an operator, pop the top two values — the first pop is the RIGHT operand, the second pop is the LEFT operand — apply the operator and push the result.Left se right scan karo. Operands ko push karo. Operator aaye toh top ke do values pop karo — pehla pop RIGHT operand hai, doosra pop LEFT operand — operator lagao aur result push kar do.

TipEvaluate 6 2 / 3 −: push 6, push 2, '/' → 6 / 2 = 3, push 3, '−' → 3 − 3 = 0.6 2 / 3 − evaluate karo: push 6, push 2, '/' → 6 / 2 = 3, push 3, '−' → 3 − 3 = 0.

Common mistakeCommon galtiGetting operand order wrong for − and / changes the answer. Second popped value OP first popped value.− aur / mein operand order galat hua toh answer badal jaata hai. Doosra popped value OP pehla popped value.

Counting stack permutationsStack permutations ginna

If 1, 2, …, n are pushed in order and pops can happen at any time, the number of possible output sequences is the nth Catalan number.Agar 1, 2, …, n order mein push hote hain aur pop kabhi bhi ho sakta hai, toh possible output sequences ki ginti nth Catalan number hoti hai.

Cₙ = C(2n, n) / (n + 1)      →  1, 1, 2, 5, 14, 42, …

TipFor n = 3 there are 5 valid sequences; 3 1 2 is impossible (after popping 3, 2 is on top of 1).n = 3 ke liye 5 valid sequences hain; 3 1 2 impossible hai (3 pop karne ke baad 2, 1 ke upar hota hai).

Quick revision

  • LIFO: push and pop happen at the top, both O(1).
  • Used for recursion, function calls, expression evaluation, undo and DFS.
  • Infix → postfix: operands go straight to output; pop operators of higher (or equal, if left-associative) precedence before pushing.
  • Postfix evaluation: push operands; on an operator, pop two (second pop is the left operand), push the result.
  • Number of valid push/pop sequences (permutations) of n elements = Catalan number C(2n, n) / (n + 1).

CH 03Queue

What is a queue?Queue kya hota hai?

A queue is a FIFO (first in, first out) list: insert at the rear, delete from the front — like a line at a ticket counter.Queue ek FIFO (first in, first out) list hai: rear pe insert, front se delete — bilkul ticket counter ki line ki tarah.

Simple vs circular queueSimple vs circular queue

In a simple array queue, the front moves forward on every dequeue, so space at the start is wasted. A circular queue wraps indices with mod n to reuse that space.Simple array queue mein har dequeue pe front aage badhta hai, toh shuru ki jagah waste ho jaati hai. Circular queue indices ko mod n se wrap karke wo jagah dobara use karta hai.

int q[N], front = 0, rear = 0;   // one slot kept empty

int isEmpty(void) { return front == rear; }
int isFull(void)  { return (rear + 1) % N == front; }
void enqueue(int x) { if (!isFull()) { q[rear] = x; rear = (rear + 1) % N; } }
int  dequeue(void)  { int x = q[front]; front = (front + 1) % N; return x; }

Common mistakeCommon galtiWith this convention a circular queue of size N holds at most N − 1 elements. Some books use a count variable instead — read the question's convention carefully.Is convention mein size N ki circular queue maximum N − 1 elements hold karti hai. Kuch books count variable use karti hain — question ka convention dhyan se padho.

VariantsVariants

TypeInsertDelete
QueueRearFront
DequeBoth endsBoth ends
Input-restricted dequeOne endBoth ends
Output-restricted dequeBoth endsOne end
Priority queueAnywhere (by priority)Highest/lowest priority first

Queue using two stacksDo stacks se queue

  • Enqueue: push onto stack S1 — O(1).
  • Dequeue: if S2 is empty, pop everything from S1 and push into S2; then pop S2.
  • Each element moves at most twice, so dequeue is amortised O(1) (worst case O(n)).
  • Enqueue: stack S1 pe push — O(1).
  • Dequeue: agar S2 khaali hai toh S1 se sab pop karke S2 mein push karo; phir S2 se pop.
  • Har element maximum do baar move hota hai, isliye dequeue amortised O(1) hai (worst case O(n)).

Stack using two queuesDo queues se stack

Either push is O(n) (rotate the new element to the front) and pop is O(1), or push is O(1) and pop is O(n). One of the two operations must be costly.Ya toh push O(n) (naye element ko rotate karke front pe lao) aur pop O(1), ya push O(1) aur pop O(n). Dono mein se ek operation mehenga hoga hi.

Where queues are usedQueue kahan use hoti hai

  • BFS traversal of graphs and level-order traversal of trees.
  • CPU scheduling (round robin), printer spooling.
  • Buffers between producer and consumer.
  • Graphs ka BFS traversal aur trees ka level-order traversal.
  • CPU scheduling (round robin), printer spooling.
  • Producer aur consumer ke beech buffers.

Quick revision

  • FIFO: enqueue at rear, dequeue at front, both O(1).
  • Circular queue of size n (one slot kept empty): full when (rear + 1) mod n = front, empty when front = rear.
  • Queue using two stacks: enqueue O(1); dequeue amortised O(1).
  • Stack using two queues: one of push/pop becomes O(n).
  • Deque allows insert/delete at both ends; priority queue is usually a heap.
  • BFS uses a queue.

CH 04Tree

TerminologyTerminology

  • Root: top node. Leaf: node with no children. Internal node: has at least one child.
  • Depth of a node: edges from the root. Height of a tree: edges on the longest root-to-leaf path (some books count nodes — check the question).
  • Degree: number of children.
  • Root: sabse upar wala node. Leaf: jiska koi child nahi. Internal node: jiska kam se kam ek child ho.
  • Node ki depth: root se kitne edges. Tree ki height: sabse lambe root-to-leaf path ke edges (kuch books nodes ginti hain — question check karo).
  • Degree: children ki ginti.

Binary tree propertiesBinary tree properties

PropertyValue
Max nodes at level l (root = 0)2ˡ
Max nodes with height h2^(h+1) − 1
Min height with n nodes⌈log₂(n + 1)⌉ − 1
Null pointers with n nodesn + 1
Leaves vs degree-2 nodesn₀ = n₂ + 1
Different binary tree shapes with n nodesC(2n, n) / (n + 1)

TraversalsTraversals

  • Level order uses a queue.
  • Inorder + preorder, or inorder + postorder → unique tree.
  • Preorder + postorder → unique only for full binary trees.
  • Level order mein queue use hoti hai.
  • Inorder + preorder, ya inorder + postorder → unique tree milta hai.
  • Preorder + postorder → sirf full binary trees ke liye unique.
void inorder(Node *t)   { if (t) { inorder(t->left);  visit(t); inorder(t->right); } }
void preorder(Node *t)  { if (t) { visit(t); preorder(t->left);  preorder(t->right); } }
void postorder(Node *t) { if (t) { postorder(t->left); postorder(t->right); visit(t); } }

Binary search tree (BST)Binary search tree (BST)

  • Left subtree < node < right subtree, so inorder traversal gives sorted order.
  • Search, insert, delete: O(h) — O(log n) if balanced, O(n) if skewed (e.g. inserting sorted data).
  • Delete a node with two children: replace it with its inorder successor (or predecessor).
  • Given only the preorder of a BST, the tree is unique (inorder is just the sorted order).
  • Left subtree < node < right subtree, isliye inorder traversal sorted order deta hai.
  • Search, insert, delete: O(h) — balanced ho toh O(log n), skewed ho toh O(n) (jaise sorted data insert karna).
  • Do children wala node delete karna: usko inorder successor (ya predecessor) se replace karo.
  • Sirf BST ka preorder diya ho toh bhi tree unique hai (inorder toh bas sorted order hai).

AVL treeAVL tree

A self-balancing BST where the balance factor (height of left − height of right) of every node is −1, 0 or +1. Rotations (LL, RR, LR, RL) restore balance after insert/delete.Ek self-balancing BST jisme har node ka balance factor (left height − right height) −1, 0 ya +1 hota hai. Insert/delete ke baad rotations (LL, RR, LR, RL) balance wapas laate hain.

Height hMin nodes N(h)
01
12
24
37
412

TipN(h) = N(h − 1) + N(h − 2) + 1. All operations are O(log n).N(h) = N(h − 1) + N(h − 2) + 1. Saare operations O(log n).

Binary heapBinary heap

  • Complete binary tree stored in an array. Max-heap: parent ≥ children.
  • 1-indexed: children of i are 2i and 2i + 1; parent is ⌊i / 2⌋.
  • Insert and delete-max: O(log n). Find max: O(1).
  • Build-heap (bottom-up heapify): O(n), not O(n log n).
  • Leaves are at indices ⌊n/2⌋ + 1 … n.
  • Complete binary tree jo array mein store hota hai. Max-heap: parent ≥ children.
  • 1-indexed: i ke children 2i aur 2i + 1; parent ⌊i / 2⌋.
  • Insert aur delete-max: O(log n). Find max: O(1).
  • Build-heap (bottom-up heapify): O(n), O(n log n) nahi.
  • Leaves indices ⌊n/2⌋ + 1 … n pe hote hain.

Common mistakeCommon galtiSearching an arbitrary element in a heap is O(n) — a heap is not a BST.Heap mein koi random element search karna O(n) hai — heap BST nahi hai.

Quick revision

  • A binary tree with n nodes has n + 1 null pointers.
  • Full binary tree: leaves = internal nodes + 1. In general, n₀ = n₂ + 1.
  • Max nodes at height h (root at height 0): 2^(h+1) − 1.
  • Inorder of a BST is sorted. Inorder + preorder (or postorder) gives a unique tree; pre + post does not.
  • BST search/insert/delete: O(h) — O(log n) balanced, O(n) skewed.
  • AVL: balance factor ∈ {−1, 0, 1}; min nodes for height h: N(h) = N(h−1) + N(h−2) + 1.
  • Binary heap: insert and delete O(log n), build O(n). In an array (1-indexed), children of i are 2i and 2i + 1.

Formulas & facts

Structurally different binary trees (n nodes)
C(2n, n) / (n + 1)
Min height with n nodes
⌈log₂(n + 1)⌉ − 1
Leaves in a heap of n nodes
⌈n / 2⌉

CH 05Linked list

Easy way to understand: a treasure huntAasan tareeka: treasure hunt

Imagine a treasure hunt. Each clue card has two things written on it: a prize (the data) and where the next clue is hidden (the pointer). You only know where the FIRST card is. To reach the 4th card you must visit cards 1, 2 and 3 first, because each card tells you where the next one is. The last card says "no more clues" — that is NULL. That is exactly how a linked list works.Ek treasure hunt socho. Har clue card pe do cheezein likhi hain: ek prize (data) aur agla clue kahan chhupa hai (pointer). Tumhe sirf PEHLE card ka pata hai. 4th card tak pahunchne ke liye pehle 1, 2 aur 3 card dekhne padenge, kyunki har card hi batata hai ki agla kahan hai. Aakhri card pe likha hai "aur clue nahi" — wahi NULL hai. Linked list bilkul aise hi kaam karti hai.

head↓
10•
→
20•
→
30•
→
NULL
Each box is a node: the left part holds the data, the • on the right is the pointer to the next node.Har box ek node hai: left part mein data, right wala • agle node ka pointer hai.
  • Node = one clue card (data + address of the next card).
  • head = the address of the first card. Lose it and you lose the whole list.
  • NULL = "no more cards". It marks the end of the list.
  • Cards can be hidden anywhere — that's why nodes don't need to sit next to each other in memory.
  • Node = ek clue card (data + agle card ka address).
  • head = pehle card ka address. Ye kho diya toh poori list kho gayi.
  • NULL = "aur cards nahi". Ye list ka end mark karta hai.
  • Cards kahin bhi chhupe ho sakte hain — isliye nodes ko memory mein ek ke baad ek baithna zaroori nahi.

What is a linked list?Linked list kya hai?

A linked list is a linear data structure made of nodes. Each node stores some data and a pointer (link) to the next node. Unlike an array, the nodes are not stored next to each other in memory — they can be anywhere, and the links hold the list together. The list is accessed through a pointer to the first node, called head. The last node's next pointer is NULL.Linked list ek linear data structure hai jo nodes se bani hoti hai. Har node kuch data aur agle node ka pointer (link) store karta hai. Array ki tarah nodes memory mein saath-saath nahi hote — kahin bhi ho sakte hain, aur links hi list ko jod ke rakhte hain. List ko pehle node ke pointer se access karte hain, jise head kehte hain. Aakhri node ka next pointer NULL hota hai.

head↓
10•
→
20•
→
30•
→
40•
→
NULL
Array: all boxes side by side in memory. Linked list: boxes anywhere, joined by arrows (pointers).Array: saare boxes memory mein saath-saath. Linked list: boxes kahin bhi, arrows (pointers) se jude hue.
struct Node {
    int data;
    struct Node *next;
};

struct Node *head = NULL;   // empty list

// head → [10 | •] → [20 | •] → [30 | NULL]

Why use a linked list?Linked list kyun use karein?

  • Dynamic size: memory is allocated one node at a time with malloc, so the list grows and shrinks as needed — no fixed capacity, no overflow until memory runs out.
  • Cheap insert/delete: adding or removing a node only changes a couple of pointers; nothing is shifted.
  • No wasted reserved space, unlike an array declared with a large fixed size.
  • Dynamic size: malloc se ek-ek node ki memory milti hai, toh list zarurat ke hisaab se badhti-ghatti hai — koi fixed capacity nahi, memory khatam hone tak overflow nahi.
  • Sasta insert/delete: node add ya remove karne mein bas do-teen pointers badalte hain; kuch shift nahi hota.
  • Bada fixed-size array declare karne jaisi reserved jagah waste nahi hoti.

Common mistakeCommon galtiThe price: no random access (reaching the i-th node takes O(i) steps), extra memory for every pointer, and poor cache performance because nodes are scattered.Keemat: random access nahi (i-th node tak pahunchne mein O(i) steps), har pointer ke liye extra memory, aur nodes bikhre hone ki wajah se cache performance kharab.

Array vs linked listArray vs linked list

OperationArraySingly linked list
Access i-th elementO(1)O(n)
SearchO(n) (O(log n) if sorted)O(n) — binary search is not efficient
Insert/delete at beginningO(n)O(1)
Insert/delete at endO(1)O(n), or O(1) insert with a tail pointer
Insert/delete in middle (position known)O(n)O(1) after reaching the node
MemoryContiguous, fixed sizeScattered, + 1 pointer per node

Types of linked listsLinked lists ke types

head↓
A•
→
B•
→
C•
→
NULL
Singly: each node points only forward.Singly: har node sirf aage point karta hai.
head↓
•A•
⇄
•B•
⇄
•C•
⇄
NULL
Doubly: each node points both backward (prev) and forward (next).Doubly: har node peeche (prev) aur aage (next) dono taraf point karta hai.
head↓
A•
→
B•
→
C•
↺ last node points back to the first
Circular: the last node points back to the first — there is no NULL.Circular: aakhri node wapas pehle ko point karta hai — koi NULL nahi.
TypeStructureKey point
Singlydata + nextOne direction only; least memory
Doublyprev + data + nextBoth directions; delete a known node in O(1)
Circular singlylast->next = headNo NULL; any node can be the start
Circular doublylast->next = head, head->prev = lastO(1) access to both ends

Creating a nodeNode banana

struct Node *newNode(int x) {
    struct Node *n = malloc(sizeof(struct Node));
    n->data = x;
    n->next = NULL;
    return n;
}

Traversal, length and searchTraversal, length aur search

Every list algorithm starts with walking the list: start at head and follow next until NULL. Never move head itself — use a temporary pointer, or you lose the list.Har list algorithm list ko walk karne se shuru hota hai: head se shuru karo aur NULL tak next follow karo. head ko khud kabhi move mat karo — temporary pointer use karo, warna list kho jaayegi.

p↓
10•
→
20•
→
30•
→
NULL
Step 1: p starts at head.Step 1: p head se shuru hota hai.
10•
→
p↓
20•
→
30•
→
NULL
Step 2: p = p->next moves p one node forward.Step 2: p = p->next se p ek node aage badhta hai.
10•
→
20•
→
p↓
30•
→
NULL
Step 3: keep moving until p becomes NULL. Searching for 30? Found here.Step 3: p NULL hone tak chalte raho. 30 dhoondh rahe ho? Yahan mil gaya.
void print(struct Node *head) {
    for (struct Node *p = head; p != NULL; p = p->next)
        printf("%d -> ", p->data);
    printf("NULL\n");
}

int length(struct Node *head) {
    int count = 0;
    while (head) { count++; head = head->next; }
    return count;
}

struct Node *search(struct Node *head, int key) {
    while (head && head->data != key) head = head->next;
    return head;   // NULL if not found
}

TipAll three are O(n) time and O(1) extra space.Teeno O(n) time aur O(1) extra space lete hain.

InsertionInsertion

head↓
10•
→
20•
→
30•
→
NULL
Insert 5 at the beginning — before: head points to 10.Shuru mein 5 insert karna — pehle: head 10 ko point karta hai.
head↓
5•
→
10•
→
20•
→
30•
→
NULL
After: new node 5 points to 10, and head now points to 5. Only 2 pointer changes → O(1).Baad mein: naya node 5, 10 ko point karta hai, aur head ab 5 ko. Sirf 2 pointer changes → O(1).
head↓
10•
→
p↓
20•
→
new↓
25•
→
30•
→
NULL
Insert 25 after node 20: first 25 → 30, then 20 → 25.Node 20 ke baad 25 insert karna: pehle 25 → 30, phir 20 → 25.
WhereTimeSteps
At beginningO(1)n->next = head; head = n
At endO(n)Walk to the last node; last->next = n
After a given node pO(1)n->next = p->next; p->next = n
At position kO(k)Walk to node k − 1, then insert after it
// At beginning
struct Node *insertFront(struct Node *head, int x) {
    struct Node *n = newNode(x);
    n->next = head;
    return n;                       // n is the new head
}

// At end
struct Node *insertEnd(struct Node *head, int x) {
    struct Node *n = newNode(x);
    if (head == NULL) return n;
    struct Node *p = head;
    while (p->next) p = p->next;    // stop at the last node
    p->next = n;
    return head;
}

// After node p
void insertAfter(struct Node *p, int x) {
    struct Node *n = newNode(x);
    n->next = p->next;              // 1. link new node forward
    p->next = n;                    // 2. then link p to it
}

Common mistakeCommon galtiOrder matters in insertAfter: if you set p->next = n first, you lose the rest of the list.insertAfter mein order zaroori hai: agar pehle p->next = n kar diya toh baaki list kho jaayegi.

DeletionDeletion

prev↓
10•
→
20•
→
30•
→
NULL
Delete 20: find the node BEFORE it (prev = 10).20 delete karna: uske PEHLE wala node dhoondo (prev = 10).
head↓
10•
→
30•
→
NULL
Set prev->next = 30, then free(20). The list skips the deleted node.prev->next = 30 set karo, phir free(20). List deleted node ko skip kar deti hai.
WhatTimeSteps
First nodeO(1)t = head; head = head->next; free(t)
Last nodeO(n)Walk to the second-last node; free its next; set next = NULL
Node with value keyO(n)Find the node before it; prev->next = cur->next
struct Node *deleteFront(struct Node *head) {
    if (!head) return NULL;
    struct Node *t = head;
    head = head->next;
    free(t);
    return head;
}

struct Node *deleteKey(struct Node *head, int key) {
    if (!head) return NULL;
    if (head->data == key) return deleteFront(head);
    struct Node *prev = head;
    while (prev->next && prev->next->data != key) prev = prev->next;
    if (prev->next) {
        struct Node *t = prev->next;
        prev->next = t->next;       // unlink
        free(t);                    // then free
    }
    return head;
}

Common mistakeCommon galtiFreeing a node before saving its next pointer is undefined behaviour. Always unlink/save first, free last.Node ka next pointer save kiye bina use free karna undefined behaviour hai. Hamesha pehle unlink/save, free sabse last.

Reversing a listList reverse karna

Walk the list once and flip every next pointer to point backwards. Three pointers are needed: prev (already-reversed part), curr (node being flipped) and next (saved so we don't lose the rest).List ko ek baar walk karo aur har next pointer ko ulta (peeche ki taraf) kar do. Teen pointers chahiye: prev (jo part reverse ho chuka), curr (jo node abhi palat rahe hain) aur next (save kiya hua, taaki baaki list na khoye).

head↓
1•
→
2•
→
3•
→
NULL
Before: 1 → 2 → 3 → NULLPehle: 1 → 2 → 3 → NULL
prev↓
1•
→
curr↓
2•
→
3•
→
NULL
Halfway: node 1 now points to NULL; curr is at 2. We flip one arrow per step.Aadhe raste: node 1 ab NULL ko point karta hai; curr 2 pe hai. Har step mein ek arrow palatte hain.
head↓
3•
→
2•
→
1•
→
NULL
After: 3 → 2 → 1 → NULL, and prev (3) is the new head.Baad mein: 3 → 2 → 1 → NULL, aur prev (3) naya head hai.
StepprevcurrList state
StartNULL11 → 2 → 3
After 1st121 → NULL, 2 → 3
After 2nd232 → 1 → NULL, 3
After 3rd3NULL3 → 2 → 1 → NULL
struct Node *reverse(struct Node *head) {
    struct Node *prev = NULL, *curr = head, *next;
    while (curr) {
        next = curr->next;   // 1. save the rest
        curr->next = prev;   // 2. flip the link
        prev = curr;         // 3. move prev forward
        curr = next;         // 4. move curr forward
    }
    return prev;             // new head
}

// Recursive version: O(n) time, O(n) stack space
struct Node *reverseRec(struct Node *head) {
    if (!head || !head->next) return head;
    struct Node *rest = reverseRec(head->next);
    head->next->next = head;
    head->next = NULL;
    return rest;
}

Fast and slow pointersFast aur slow pointers

Two pointers moving at different speeds solve many list problems in one pass with O(1) extra space.Alag speed se chalne wale do pointers kai list problems ek hi pass mein O(1) extra space se solve kar dete hain.

slow/fast↓
1•
→
2•
→
3•
→
4•
→
5•
→
NULL
Start: slow and fast both at head.Shuru: slow aur fast dono head pe.
1•
→
slow↓
2•
→
fast↓
3•
→
4•
→
5•
→
NULL
One step: slow moves 1 node, fast moves 2.Ek step: slow 1 node chalta hai, fast 2.
1•
→
2•
→
slow↓
3•
→
4•
→
fast↓
5•
→
NULL
End: fast reaches the last node, slow is exactly in the middle (3).End: fast aakhri node pe pahunchta hai, slow theek beech (3) mein hota hai.
  • Cycle start: after slow and fast meet, move one pointer back to head and advance both one step at a time — they meet at the first node of the cycle.
  • k-th node from the end: move a pointer k steps ahead, then move both together until the leading one hits NULL.
  • Palindrome check: find the middle, reverse the second half, compare both halves.
  • Cycle start: slow aur fast milne ke baad ek pointer ko wapas head pe le jao aur dono ko ek-ek step chalao — wo cycle ke pehle node pe milenge.
  • End se k-th node: ek pointer ko k steps aage le jao, phir dono ko saath chalao jab tak aage wala NULL na ho.
  • Palindrome check: middle dhoondo, second half reverse karo, dono halves compare karo.
// Middle node (for even length, returns the second middle)
struct Node *middle(struct Node *head) {
    struct Node *slow = head, *fast = head;
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

// Floyd's cycle detection
int hasCycle(struct Node *head) {
    struct Node *slow = head, *fast = head;
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) return 1;
    }
    return 0;
}

Merging two sorted listsDo sorted lists merge karna

a↓
1•
→
4•
→
7•
→
NULL
List aList a
b↓
2•
→
3•
→
9•
→
NULL
List bList b
head↓
1•
→
2•
→
3•
→
4•
→
7•
→
9•
→
NULL
Merged: always take the smaller front node.Merged: hamesha chhota front node lo.
struct Node *merge(struct Node *a, struct Node *b) {
    struct Node dummy, *tail = &dummy;
    dummy.next = NULL;
    while (a && b) {
        if (a->data <= b->data) { tail->next = a; a = a->next; }
        else                    { tail->next = b; b = b->next; }
        tail = tail->next;
    }
    tail->next = a ? a : b;   // attach the leftover part
    return dummy.next;
}

TipO(m + n) time, O(1) extra space. This is the merge step of merge sort, which is the preferred way to sort a linked list (O(n log n), no random access needed).O(m + n) time, O(1) extra space. Ye merge sort ka merge step hai — linked list sort karne ka best tareeka (O(n log n), random access ki zarurat nahi).

Doubly linked listDoubly linked list

Each node has prev and next pointers. You can walk in both directions, and given a pointer to a node you can delete it in O(1) because its predecessor is directly available.Har node mein prev aur next pointers hote hain. Dono direction mein walk kar sakte ho, aur kisi node ka pointer diya ho toh use O(1) mein delete kar sakte ho kyunki uska predecessor seedha available hai.

head↓
•10•
⇄
p↓
•20•
⇄
•30•
⇄
NULL
Each node has prev • | data | next •. You can walk both ways.Har node mein prev • | data | next •. Dono taraf chal sakte ho.
head↓
•10•
⇄
•30•
⇄
NULL
Delete p (20) directly: 10 → 30 and 30 ← 10. No need to search for the previous node.p (20) ko seedha delete karo: 10 → 30 aur 30 ← 10. Previous node dhoondhne ki zarurat nahi.
struct DNode {
    int data;
    struct DNode *prev, *next;
};

// Delete node p in O(1)
void deleteNode(struct DNode **head, struct DNode *p) {
    if (p->prev) p->prev->next = p->next;
    else         *head = p->next;          // p was the head
    if (p->next) p->next->prev = p->prev;
    free(p);
}

// Insert n after p: four pointer updates
void insertAfterD(struct DNode *p, struct DNode *n) {
    n->prev = p;
    n->next = p->next;
    if (p->next) p->next->prev = n;
    p->next = n;
}

Common mistakeCommon galtiInserting into a doubly list needs 4 pointer changes (2 in the new node, 2 in its neighbours); deleting needs 2. GATE often asks which line in such code is wrong — check the NULL cases at the head and tail.Doubly list mein insert ke liye 4 pointer changes chahiye (2 naye node mein, 2 neighbours mein); delete ke liye 2. GATE aksar poochta hai ki aise code mein kaunsi line galat hai — head aur tail pe NULL cases check karo.

Circular linked listCircular linked list

The last node points back to the first, so there is no NULL. Loops must stop when they come back to the starting node.Aakhri node wapas pehle ko point karta hai, isliye koi NULL nahi hota. Loops ko tab rukna chahiye jab wo starting node pe wapas aa jaayein.

first↓
A•
→
B•
→
C•
→
last↓
D•
↺ last node points back to the first
No NULL at the end: after D, we come back to A. Keeping a pointer to the LAST node (D) gives O(1) access to both ends.End mein NULL nahi: D ke baad wapas A aate hain. LAST node (D) ka pointer rakhne se dono ends O(1) mein milte hain.
  • Keep a pointer to the LAST node instead of the first: then both the first (last->next) and the last node are reachable in O(1), so insert at front and at end are both O(1).
  • Used for round-robin scheduling and circular buffers.
  • Josephus problem is a classic circular-list application.
  • Pehle node ki jagah LAST node ka pointer rakho: tab first (last->next) aur last dono O(1) mein milte hain, toh front aur end dono pe insert O(1).
  • Round-robin scheduling aur circular buffers mein use hota hai.
  • Josephus problem circular list ki classic application hai.
void printCircular(struct Node *head) {
    if (!head) return;
    struct Node *p = head;
    do {
        printf("%d ", p->data);
        p = p->next;
    } while (p != head);
}

Complexity summaryComplexity summary

OperationSinglyDoublyCircular (last pointer)
Insert at frontO(1)O(1)O(1)
Insert at endO(n)O(n) / O(1) with tailO(1)
Delete frontO(1)O(1)O(1)
Delete endO(n)O(1) with tailO(n)
Delete given nodeO(n)O(1)O(n)
SearchO(n)O(n)O(n)
ReverseO(n)O(n)O(n)

Common mistakeCommon galtiDeleting the last node of a singly or circular list is O(n) even with a tail pointer, because you need the second-last node.Singly ya circular list ka last node delete karna tail pointer ke saath bhi O(n) hai, kyunki second-last node chahiye.

GATE-style practiceGATE-style practice

  • Q1. In a singly linked list with only a head pointer, which needs O(n): insert at front, delete front, or insert at end? → Insert at end.
  • Q2. A circular list is accessed by a pointer to the last node. Cost of inserting at the front and at the end? → Both O(1).
  • Q3. Best sorting algorithm for a linked list? → Merge sort, O(n log n).
  • Q4. Can binary search run in O(log n) on a sorted linked list? → No; finding the middle takes O(n) each time.
  • Q5. Given only a pointer p to a node (not the last) in a singly list, delete it in O(1)? → Copy p->next's data into p, then delete p->next.
  • Q6. Minimum extra pointers to reverse a singly list iteratively? → Three (prev, curr, next).
  • Q1. Sirf head pointer wali singly linked list mein kya O(n) leta hai: front pe insert, front delete, ya end pe insert? → End pe insert.
  • Q2. Circular list last node ke pointer se access hoti hai. Front aur end pe insert ki cost? → Dono O(1).
  • Q3. Linked list ke liye best sorting algorithm? → Merge sort, O(n log n).
  • Q4. Sorted linked list pe binary search O(log n) mein chal sakta hai? → Nahi; har baar middle dhoondhne mein O(n) lagta hai.
  • Q5. Singly list mein sirf ek node ka pointer p diya hai (last nahi), use O(1) mein delete karo? → p->next ka data p mein copy karo, phir p->next delete kar do.
  • Q6. Singly list ko iteratively reverse karne ke liye minimum extra pointers? → Teen (prev, curr, next).

Quick revision

  • Insert/delete at the head is O(1); access by index is O(n).
  • Finding the middle: slow pointer moves 1, fast pointer moves 2.
  • Cycle detection: Floyd's tortoise and hare, O(n) time, O(1) space.
  • Reversing a singly linked list: three pointers (prev, curr, next), O(n).
  • Deleting a node in a singly list needs its predecessor; a doubly linked list does it in O(1) given the node.
  • Merging two sorted lists of size m and n: O(m + n).

CH 06Graph and hashing

Graph basicsGraph basics

  • A graph G = (V, E): V vertices, E edges. Directed or undirected, weighted or unweighted.
  • Sum of all degrees = 2E (handshaking lemma), so the number of odd-degree vertices is even.
  • Max edges: V(V − 1)/2 undirected, V(V − 1) directed.
  • A tree is a connected acyclic graph with V − 1 edges.
  • Graph G = (V, E): V vertices, E edges. Directed ya undirected, weighted ya unweighted.
  • Saari degrees ka sum = 2E (handshaking lemma), isliye odd-degree vertices ki ginti hamesha even hoti hai.
  • Max edges: undirected mein V(V − 1)/2, directed mein V(V − 1).
  • Tree ek connected acyclic graph hai jisme V − 1 edges hote hain.

RepresentationsRepresentations

Adjacency matrixAdjacency list
SpaceO(V²)O(V + E)
Check edge (u, v)O(1)O(degree of u)
List neighbours of uO(V)O(degree of u)
Best forDense graphsSparse graphs

BFS and DFSBFS aur DFS

BFSDFS
UsesQueueStack / recursion
Time (adj. list)O(V + E)O(V + E)
Time (adj. matrix)O(V²)O(V²)
FindsShortest path in unweighted graphsCycles, topological order, components

TipIn BFS of an undirected graph there are no forward edges; in DFS of an undirected graph there are no cross edges.Undirected graph ke BFS mein forward edges nahi hote; undirected graph ke DFS mein cross edges nahi hote.

HashingHashing

A hash function maps a key to a slot in a table of size m, giving average O(1) search, insert and delete. Collisions (two keys in one slot) are handled by chaining or open addressing.Hash function ek key ko size m ki table ke ek slot pe map karta hai, jisse search, insert aur delete average O(1) mein hote hain. Collisions (do keys ek hi slot mein) ko chaining ya open addressing se handle karte hain.

Division method:  h(k) = k mod m      (choose m prime, not close to a power of 2)
Load factor:      α = n / m

Collision resolutionCollision resolution

MethodProbe sequenceProblem
ChainingLinked list at each slotExtra memory for pointers
Linear probingh(k) + iPrimary clustering
Quadratic probingh(k) + c₁i + c₂i²Secondary clustering
Double hashingh₁(k) + i·h₂(k)None of the above (best spread)

Expected search cost (uniform hashing)Expected search cost (uniform hashing)

MethodUnsuccessfulSuccessful
Chaining1 + α1 + α/2
Open addressing1 / (1 − α)(1/α) ln(1 / (1 − α))

Common mistakeCommon galtiIn open addressing α must be < 1 (the table can fill up); in chaining α can be greater than 1.Open addressing mein α < 1 hona chahiye (table bhar sakti hai); chaining mein α 1 se zyada bhi ho sakta hai.

Quick revision

  • Adjacency matrix: O(V²) space, O(1) edge check. Adjacency list: O(V + E) space.
  • BFS and DFS both take O(V + E) with an adjacency list.
  • Undirected graph: max edges = V(V − 1) / 2.
  • Hashing: chaining has no clustering; linear probing causes primary clustering, quadratic probing causes secondary clustering.
  • Double hashing avoids both kinds of clustering.

Formulas & facts

Load factor α
n / m (keys / slots)
Chaining, unsuccessful search
1 + α
Open addressing, unsuccessful search
1 / (1 − α)
Division method
h(k) = k mod m
CH 01Array4 points · 4 formulas→CH 02Stack5 points→CH 03Queue6 points→CH 04Tree7 points · 3 formulas→CH 05Linked list6 points→CH 06Graph and hashing5 points · 4 formulas→
← Previous subjectC ProgrammingNext subject →Algorithms