IAE Academy

GATE CS · DA

Arrays, stacks, queues and linked lists

GATE CS/IT notes on arrays, stacks, queues and linked lists. Covers array address calculation (1-D, 2-D row- and column-major, arbitrary lower bounds, packed lower-triangular storage) and stacks: infix-to-postfix conversion, postfix and prefix evaluation, stack-permutation feasibility with the 3-1-2 pattern rule and the Catalan count, and two stacks in one array. Then circular queues under both full/empty conventions, deques, and queues and stacks built from each other. Then singly, doubly and circular linked lists (insert, delete including the O(1) data-copy technique, reversal) and Floyd's cycle detection with the correct meeting-point relation (a mod c). Closes with a master complexity table and a list of exam traps.

13 previous-year questions · 13 solved · 6 practice questions

Arrays as Structures

An array is a fixed-size, contiguous block of memory holding elements of the same type. Every element occupies the same number of bytes and the elements are laid out back to back. So the address of any element can be computed directly from its index, which gives arrays O(1) random access, unlike linked structures. The two recurring calculations are an element's address (1-D or 2-D, row-major or column-major) and the cost of insertion or deletion, which requires shifting elements.

Conventions used throughout these notes, unless a question says otherwise: C semantics, int is 4 bytes and char is 1 byte, arrays are 0-indexed and stored row-major (as C stores them), and complexities are worst case.

1-D ARRAY ELEMENT ADDRESS

w = size of one element in bytes; L = lower bound of the index (L = 0 for a C array, giving Base + i*w); Base = address of the first element A[L].

2-D ARRAY ADDRESS (ROW-MAJOR, 0-INDEXED)

cols = number of columns. C stores 2-D arrays row-major, and these notes assume row-major unless a question says column-major. For column-major, whole columns are stored one after another: Base + (j*rows + i)*w, where rows = number of rows.

2-D ARRAY ADDRESS WITH ARBITRARY LOWER BOUNDS (ROW-MAJOR)

Array declared as A[L1..U1][L2..U2]; n_c = U2 - L2 + 1 is the number of columns; Base = address of A[L1][L2]. Column-major: Base + ((j - L2)*n_r + (i - L1))*w with n_r = U1 - L1 + 1.

LOWER-TRIANGULAR MATRIX STORED PACKED (ROW-MAJOR)

Holds for a 0-indexed n x n lower-triangular matrix (only entries with i >= j are stored) packed row by row into a 1-D array. Rows 0 to i-1 contribute 1 + 2 + ... + i = i(i+1)/2 entries. Address = Base + index*w. The packed array holds n(n+1)/2 elements.

Properties and costs of arrays

  1. Size is fixed when the array is created (in C a plain array cannot be resized). Elements are homogeneous and stored contiguously.

  2. Random access by index: O(1), since the address formula needs no traversal.

  3. Search in an unsorted array: O(n). In a sorted array, binary search gives O(log n).

  4. Insert/delete at an arbitrary position: O(n) worst case, because every element after that position must shift by one slot.

  5. Insert/delete at the end (when space remains in the array): O(1).

EXAM TIP

Before computing an address, fix three things from the question: the index lower bound (0, 1, or something else such as A[-5..5]), the storage order (row-major unless told column-major), and the element size w in bytes. Substituting i where the formula needs i - L is the usual source of an off-by-one-row error.

Stacks: Push/Pop, Infix-to-Postfix, Postfix Evaluation and Stack Permutations

A stack is a LIFO (last-in, first-out) structure supporting push (insert at top), pop (remove from top), peek/top (read the top without removing it), and isEmpty/isFull. Each is O(1) whether the stack is built on a fixed-size array or on a linked list. The array version keeps a top index and is full when top == capacity-1; a push in that state overflows. The linked-list version pushes and pops at the head, so no traversal is ever needed.

#define MAXSIZE 100
int stackArr[MAXSIZE];
int top = -1;

int isEmpty(void) { return top == -1; }
int isFull(void)  { return top == MAXSIZE - 1; }

void push(int x) {
    if (isFull()) { /* overflow */ return; }
    stackArr[++top] = x;
}

int pop(void) {
    if (isEmpty()) { /* underflow */ return -1; } /* -1 is only an illustrative sentinel */
    return stackArr[top--];
}

Stacks are used for expression conversion and evaluation, function-call and recursion bookkeeping, parenthesis matching and backtracking. They also answer whether a given output order can be produced from an input order using only push and pop.

Operator precedence and associativity (as assumed in infix expressions)

Group (high to low)

Operators

Associativity

1 (highest)

( )

not applicable (parentheses are resolved first)

2

^ (exponentiation)

right to left

3

  • /

left to right

4 (lowest)

+ -

left to right

In these infix-expression questions ^ means exponentiation. It is NOT C's ^ operator, which is bitwise XOR and has a much lower precedence.

Infix -> postfix conversion (stack-based)

  1. Scan the infix expression left to right, one token at a time.

  2. If the token is an operand, append it directly to the output.

  3. If the token is '(', push it onto the operator stack.

  4. If the token is ')', pop operators from the stack and append them to the output until a '(' is popped. Discard both parentheses; they never appear in the output.

  5. If the token is an operator o: while the stack is non-empty, its top is not '(', and either precedence(top) > precedence(o) or (precedence(top) == precedence(o) and o is left-associative), pop the top operator to the output. Then push o.

  6. After the scan ends, pop the remaining operators from the stack to the output, top first.

Postfix and prefix expression evaluation (stack-based)

  1. Postfix: scan left to right.

  2. If the token is an operand, push its value.

  3. If the token is a binary operator, pop the top value (call it b), then pop the next value (call it a), compute a <operator> b and push the result. The first value popped is the RIGHT operand, which matters for '-', '/' and '^'.

  4. After the last token, exactly one value remains on the stack; that is the result.

  5. Prefix: scan RIGHT to left with the same push rule. On an operator, the first value popped is the LEFT operand: pop a, pop b, push a <operator> b. Example: prefix - 8 2 gives push 2, push 8, then '-' pops 8 and 2 and computes 8 - 2 = 6.

WORKED EXAMPLE · CONVERT AND EVALUATE

Convert (3 + 4) * 2 - 8 / 4 to postfix, then evaluate it.

Solution
  1. '(': push; stack = [ ( ].

  2. '3': output = 3.

  3. '+': the top is '(', so nothing is popped; push; stack = [ ( + ].

  4. '4': output = 3 4.

  5. ')': pop '+' to the output, then pop '(' and discard it; output = 3 4 +, stack = [ ].

  6. '': the stack is empty; push; stack = [ ].

  7. '2': output = 3 4 + 2.

  8. '-': precedence('') > precedence('-'), so pop '' to the output; the stack is now empty; push '-'; output = 3 4 + 2 *, stack = [ - ].

  9. '8': output = 3 4 + 2 * 8.

  10. '/': the top is '-', which has lower precedence than '/', so nothing is popped; push '/'; stack = [ - / ].

  11. '4': output = 3 4 + 2 * 8 4.

  12. End of scan: pop '/' then '-'; final postfix = 3 4 + 2 * 8 4 / -.

  13. Evaluation: push 3, push 4; '+' pops 4 and 3 and pushes 3+4 = 7; push 2; '*' pops 2 and 7 and pushes 7*2 = 14; push 8, push 4; '/' pops 4 and 8 and pushes 8/4 = 2; '-' pops 2 and 14 and pushes 14-2 = 12.

  14. One value remains on the stack: 12.

Answer: Postfix: 3 4 + 2 * 8 4 / - ; value = 12

Testing whether an output sequence is a valid stack permutation of inputs pushed in order 1..n

  1. Keep an auxiliary stack S (initially empty) and a counter i = 1 for the next input value available to push.

  2. For each target value t, taken left to right from the desired output: while S is empty or top(S) != t, push i onto S and increment i. This is possible only while i <= n.

  3. If i > n and top(S) is still not t, the output is NOT achievable. Stop and report it infeasible.

  4. Otherwise top(S) == t: pop S, which emits t, and move to the next target.

  5. If every target is consumed this way, the sequence is a valid stack permutation.

  6. Equivalent quick check (the 3-1-2 pattern): the output is achievable if and only if there are no three positions p < q < r whose values satisfy out[q] < out[r] < out[p]. In words: once a value x is output, any smaller values output after it must appear in decreasing order.

NUMBER OF DISTINCT VALID STACK-PERMUTATION OUTPUTS OF N ELEMENTS

n distinct elements pushed in a fixed order (1, 2, ..., n) through one stack, with pushes and pops interleaved freely. C_n (the nth Catalan number) counts the distinct output sequences: C_1 = 1, C_2 = 2, C_3 = 5, C_4 = 14, C_5 = 42.

Two stacks in one array. Two stacks can share an array of size N without wasting space: stack 1 grows upward from index 0 and stack 2 grows downward from index N-1. Overflow happens only when the whole array is used.

#define N 100
int arr[N];
int top1 = -1;
int top2 = N;

void push1(int x) {
    if (top1 + 1 == top2) { /* overflow: array full */ return; }
    arr[++top1] = x;
}

void push2(int x) {
    if (top1 + 1 == top2) { /* overflow: array full */ return; }
    arr[--top2] = x;
}

The array is full exactly when top1 + 1 == top2.

EXAM TIP

Because ^ is right-associative, an incoming '^' does NOT pop a '^' already on the stack: the precedences are equal but the operator is right-associative, so the pop condition fails. So a ^ b ^ c becomes a b c ^ ^. In postfix evaluation the first value popped is the right operand; in prefix evaluation it is the left operand. Sanity checks for stack permutations: the fully decreasing output (n, n-1, ..., 1) and the output identical to the input order are both always achievable.

Queues: Linear, Circular, Deque, Queue Using Two Stacks

A queue is FIFO (first-in, first-out): enqueue inserts at the rear and dequeue removes from the front. A naive array-based linear queue only ever moves front and rear forward. After some dequeues the freed slots at the start of the array are never reused, so the queue can report 'full' while space exists. Treating the array as circular fixes this.

CIRCULAR QUEUE INDEX WRAPAROUND

SIZE = capacity of the underlying array. Every dequeue advances front by the same rule: front = (front + 1) mod SIZE.

Circular queue full/empty tests (two common conventions)

  1. Convention 1, one slot sacrificed: front is the index of the first element and rear is the index of the next free slot, both starting at 0. Enqueue writes q[rear] and then advances rear; dequeue reads q[front] and then advances front. Empty when front == rear; full when (rear + 1) mod SIZE == front. Number of elements = (rear - front + SIZE) mod SIZE. Only SIZE - 1 elements fit.

  2. Convention 2, an explicit count: empty when count == 0, full when count == SIZE. All SIZE slots are usable, but count must be updated on every enqueue and dequeue.

  3. Other variants exist (for example rear starting at -1, or a separate 'full' flag). The capacity follows from whichever full test the question's code uses, so read it before answering.

Convention 2 in C:

#define SIZE 100
int q[SIZE];
int front = 0, rear = -1, count = 0;

void enqueue(int x) {
    if (count == SIZE) { /* full */ return; }
    rear = (rear + 1) % SIZE;
    q[rear] = x;
    count++;
}

int dequeue(void) {
    if (count == 0) { /* empty */ return -1; } /* -1 is only an illustrative sentinel */
    int x = q[front];
    front = (front + 1) % SIZE;
    count--;
    return x;
}

A deque (double-ended queue) allows insertion and deletion at BOTH ends. An input-restricted deque allows insertion at only one end but deletion at both. An output-restricted deque allows deletion at only one end but insertion at both. A deque can act as a stack (use only one end) or as a plain queue (insert at one end, delete at the other).

Implementing a queue using two stacks: two standard methods

Method

Enqueue cost

Dequeue cost

How it works

Expensive enqueue

O(n)

O(1)

To enqueue x: move everything from stack1 to stack2, push x onto stack1 (now empty), then move everything back from stack2 to stack1. The oldest element stays on top of stack1, so dequeue is a single pop.

Expensive dequeue (amortized O(1))

O(1)

O(1) amortized, O(n) worst case

Always push new elements onto stack in. To dequeue: if stack out is empty, pop everything from in and push it onto out (reversing the order), then pop from out; if out is non-empty, pop from it directly. Each element moves from in to out at most once, so the amortized cost per operation is O(1).

/* amortized O(1) queue using two stacks (pseudo-code) */
Stack in, out;

enqueue(x):
    push(in, x)

dequeue():
    if isEmpty(out):
        while not isEmpty(in):
            push(out, pop(in))
    return pop(out)    /* underflow if both stacks are empty */

Implementing a stack using two queues: two standard methods

Method

Push cost

Pop cost

How it works

Expensive pop

O(1)

O(n)

Push: enqueue onto q1. Pop: dequeue n-1 elements from q1 and enqueue them onto q2, dequeue and return the last element of q1, then swap the names of q1 and q2.

Expensive push

O(n)

O(1)

Push x: enqueue x onto the empty q2, dequeue every element of q1 and enqueue it onto q2, then swap the names. The newest element is always at the front of q1, so pop is a single dequeue.

EXAM TIP

When a question gives an array size N for a circular queue, find the full test in its code or wording first. If full means (rear + 1) mod N == front, capacity is N - 1; with a count variable it is N. For the two-stack queue, keep worst-case cost (O(n) for the one dequeue that refills out) separate from amortized cost (O(1) averaged over any sequence of operations), and answer the one the question asks for.

Linked Lists: Singly, Doubly and Circular (Structure, Insert, Delete, Reverse)

A linked list stores elements as nodes that can sit anywhere in memory. Each node holds data plus one or more pointers to neighbouring nodes. The list gives up O(1) random access, since you must walk from a known pointer. In exchange, insertion and deletion are O(1) once you hold a pointer to the right node, with no shifting.

/* singly linked list node */
struct SNode {
    int data;
    struct SNode *next;
};

/* doubly linked list node */
struct DNode {
    int data;
    struct DNode *prev;
    struct DNode *next;
};

In a circular singly linked list the last node's next points back to the head instead of NULL. A circular doubly linked list also has the head's prev pointing to the last node. Circular lists suit any traversal that should wrap around, for example round-robin scheduling.

Insertion and deletion on a singly linked list

  1. Insert at head: create a new node, set its next to the current head, and make head point to the new node. O(1).

  2. Insert after a known node p: new->next = p->next; then p->next = new;. O(1).

  3. Insert before a known node p: relinking needs p's predecessor, which takes an O(n) scan from the head. The O(1) alternative: insert the new node after p, then swap the data fields of p and the new node.

  4. Insert at tail: O(1) if a tail pointer is maintained, O(n) if you must walk to the last node.

  5. Delete the node after a known node p: temp = p->next; p->next = temp->next; free(temp);. O(1).

  6. Delete the head: temp = head; head = head->next; free(temp);. O(1).

  7. Delete the tail: O(n) even with a tail pointer, because the second-last node's next must become NULL and it can only be found by walking from the head.

  8. Delete a known node p when only p is given: relinking needs the predecessor (O(n)). If p is NOT the last node, the O(1) data-copy technique works: copy the next node's data into p, then unlink and free that next node. It cannot delete the last node.

  9. Delete by value: an O(n) scan to find the node, keeping a prev pointer during the scan.

O(1) deletion of a given node p (p must not be the last node):

struct SNode *t = p->next;
p->data = t->data;
p->next = t->next;
free(t);

Doubly linked list: insert node q after node p, and delete node p. The NULL checks cover the ends of the list.

/* insert q after p */
q->prev = p;
q->next = p->next;
if (p->next != NULL)
    p->next->prev = q;
p->next = q;

/* delete p */
if (p->prev != NULL)
    p->prev->next = p->next;
else
    head = p->next;
if (p->next != NULL)
    p->next->prev = p->prev;
free(p);

In the insertion, p->next = q; must come last, because the lines before it still need the old p->next.

Iterative in-place reversal of a singly linked list:

struct SNode* reverse(struct SNode *head) {
    struct SNode *prev = NULL;
    struct SNode *curr = head;
    while (curr != NULL) {
        struct SNode *nextNode = curr->next; /* save before overwriting */
        curr->next = prev;
        prev = curr;
        curr = nextNode;
    }
    return prev; /* new head */
}

WORKED EXAMPLE · TRACE AN IN-PLACE REVERSAL

Trace reverse() above on the list 10 -> 20 -> 30 -> NULL.

Solution
  1. Initial: prev = NULL, curr = 10.

  2. Iteration 1: nextNode = 20; 10->next = NULL; prev = 10; curr = 20. Reversed part: 10 -> NULL; the rest, 20 -> 30 -> NULL, is untouched.

  3. Iteration 2: nextNode = 30; 20->next = 10; prev = 20; curr = 30. Reversed part: 20 -> 10 -> NULL.

  4. Iteration 3: nextNode = NULL; 30->next = 20; prev = 30; curr = NULL. Reversed part: 30 -> 20 -> 10 -> NULL.

  5. The loop ends (curr == NULL) and the function returns prev = 30, the new head.

Answer: Reversed list: 30 -> 20 -> 10 -> NULL, in O(n) time and O(1) extra space.

Traversing a circular singly linked list. The next pointers never become NULL, so the loop stops on returning to the head. A do-while visits the head exactly once:

if (head != NULL) {
    struct SNode *p = head;
    do {
        printf("%d ", p->data);
        p = p->next;
    } while (p != head);
}

Complexity comparison: array vs singly linked list vs doubly linked list (worst case)

Operation

Array

Singly linked list

Doubly linked list

Access by index

O(1)

O(n)

O(n)

Search (unsorted)

O(n)

O(n)

O(n)

Insert/delete at front

O(n) (shifting)

O(1)

O(1)

Insert at end

O(1) if space remains

O(1) with tail pointer, else O(n)

O(1) with tail pointer, else O(n)

Delete at end

O(1)

O(n), even with a tail pointer

O(1) with tail pointer

Insert/delete given a pointer to the spot

O(n) (shifting)

Insert after p: O(1). Delete p: O(n) by relinking; O(1) by data copy if p is not the last node

O(1) (has both prev and next)

EXAM TIP

In any pointer-rewiring code, read curr->next into a temporary BEFORE you overwrite curr->next; otherwise the rest of the list is lost. When deleting from a singly linked list by scanning, carry a prev pointer, because you cannot step backwards. A circular list's loop must end on p != head, typically with a do-while, never on p != NULL.

Cycle Detection and List-Manipulating Functions

Floyd's cycle detection ('tortoise and hare') walks two pointers through the list at different speeds: slow advances one node per iteration and fast advances two. If the list has no cycle, fast reaches NULL. If it has a cycle, both pointers eventually enter it. From then on the gap between them shrinks by exactly one link per iteration, so fast cannot jump over slow and they must land on the same node. The method takes O(n) time and O(1) extra space; a hash-set approach needs O(n) extra space.

int hasCycle(struct SNode *head) {
    struct SNode *slow = head, *fast = head;
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast)
            return 1; /* cycle found */
    }
    return 0; /* fast reached the end: no cycle */
}

Where they meet. Let be the number of links from the head to the first node of the cycle, and the number of nodes in the cycle. Suppose they meet after slow has taken steps, where is the meeting node's distance past the cycle start (). fast has taken steps, and the difference must be a whole number of laps, a multiple of . So : walking links forward from the meeting node lands exactly on the cycle start, possibly after going round the loop.

FLOYD CYCLE-DETECTION MEETING PROPERTY

a = links from the head to the cycle's start node; c = number of nodes in the cycle; d = the SMALLEST number of links followed forward from the first meeting node to the cycle start (0 to c-1). Holds when both pointers start at the head and slow moves 1 and fast moves 2 links per iteration. d equals a itself only when a < c. In every case, advancing a links from the meeting node reaches the cycle start, which is why the reset-to-head method below works.

Finding the start node of a detected cycle

  1. After hasCycle finds slow == fast, leave fast at the meeting node and set a new pointer p1 = head.

  2. Advance p1 and fast one link at a time, together.

  3. After exactly a moves, p1 reaches the cycle start. By the property above, fast is there too, having possibly gone round the loop, so the node where they meet is the cycle's start.

  4. The extra time is O(n) and the extra space is two or three pointers.

WORKED EXAMPLE · TRACE A LIST-MANIPULATING FUNCTION: FINDING THE MIDDLE NODE WITH SLOW/FAST POINTERS

For the 6-node list 4 -> 9 -> 2 -> 7 -> 5 -> 1 -> NULL, trace the movement of slow and fast in:

struct SNode* findMiddle(struct SNode *head) {
    struct SNode *slow = head, *fast = head;
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

State which node it returns, and why this is O(n) time with O(1) space.

Solution
  1. Start: slow = 4, fast = 4.

  2. Check: fast (4) is not NULL and fast->next (9) is not NULL. Move: slow = 9, fast = 2.

  3. Check: fast (2) and fast->next (7) are not NULL. Move: slow = 2, fast = 5.

  4. Check: fast (5) and fast->next (1) are not NULL. Move: slow = 7, fast = 1->next = NULL.

  5. Check: fast == NULL, so the loop ends and the function returns slow = 7.

  6. No memory is allocated and each pointer only moves forward through the list, so the time is O(n) and the extra space is O(1).

Answer: Returns the node holding 7, the 4th node (1-indexed). The two middle nodes of a 6-node list are the 3rd (2) and the 4th (7), so with this loop guard an even-length list returns the SECOND middle. With the guard fast->next != NULL && fast->next->next != NULL (and a non-empty list), it returns the first middle (2) instead. For an odd-length list both guards return the single middle node.

EXAM TIP

For any slow/fast-pointer function, first note the step ratio (1 vs 2 is the cycle-detect / find-middle pattern) and the exact loop guard. The guard decides whether an even-length list yields the first or the second middle node. Dry-run the code on a small concrete list, one of odd and one of even length, instead of reasoning abstractly. For the cycle-start distance, use a mod c, not a.

Complexity Summary and Exam Traps

Master complexity table (worst case unless stated)

Structure / operation

Time complexity

Notes / conditions

Array: access by index

O(1)

Only the address formula is needed, no traversal

Array: insert/delete at arbitrary position

O(n)

Elements after the position shift by one

Stack: push, pop, peek

O(1)

For both a fixed-capacity array and a linked list (push/pop at the head)

Infix to postfix conversion

O(n)

n = number of tokens; each operator is pushed and popped at most once

Postfix / prefix evaluation

O(n)

n = number of tokens

Stack-permutation feasibility test

O(n)

n = length of the sequence; each input pushed once, each output popped once

Circular queue: enqueue, dequeue

O(1)

Modulo arithmetic for wraparound, no shifting

Queue via two stacks: enqueue

O(n) or O(1)

O(n) in the 'expensive enqueue' method, O(1) in the 'expensive dequeue' method

Queue via two stacks: dequeue

O(1), or O(1) amortized

O(1) in the 'expensive enqueue' method; O(1) amortized and O(n) worst case in the other

Stack via two queues

push O(1) and pop O(n), or push O(n) and pop O(1)

Depends on which operation does the transfer

Singly linked list: insert after a known node; delete the node after a known node

O(1)

Pointer relinking only

Singly linked list: delete a known node p

O(n) by relinking; O(1) by data copy

The data-copy technique fails when p is the last node

Singly linked list: delete the last node

O(n)

Even with a tail pointer: the second-last node must be found

Doubly linked list: insert/delete at a known node

O(1)

Both prev and next are available

Linked list: search by value / access by index

O(n)

No random access; walk from the head (a doubly linked list can also walk backwards from a known node)

Linked list reversal

O(n) time, O(1) space

Iterative three-pointer method; the recursive version uses O(n) stack space

Cycle detection (Floyd's)

O(n) time, O(1) space

Detect: slow and fast meet. Locate the start: reset one pointer to the head, advance both one link at a time until they meet

Formula-sheet recap

  1. 1-D address: Base + (i - L)*w, which is Base + i*w for a 0-indexed C array.

  2. 2-D row-major address (0-indexed): Base + (i*cols + j)*w. Column-major: Base + (j*rows + i)*w. With lower bounds: Base + ((i - L1)*n_c + (j - L2))*w.

  3. Packed lower-triangular (0-indexed, row-major, i >= j): index = i(i+1)/2 + j.

  4. Circular queue wraparound: index = (index + 1) mod SIZE, for both front and rear. With one slot sacrificed: count = (rear - front + SIZE) mod SIZE and capacity = SIZE - 1.

  5. Stack permutations of n distinct elements: C_n = (2n)! / ((n+1)! * n!). An output is achievable if and only if it contains no 3-1-2 pattern.

  6. Two stacks in one array of size N: overflow exactly when top1 + 1 == top2.

  7. Floyd: the smallest forward distance from the meeting node to the cycle start is a mod c, where a = tail length and c = cycle length.

EXAM TIP

Traps to check, in order. (1) Array indexing: 0-based, 1-based or another lower bound? Read the question. (2) Is there a right-associative operator (^) in the infix expression? Then an incoming '^' does not pop an equal-precedence '^'. (3) Does the circular queue sacrifice a slot (capacity N - 1) or track a count (capacity N)? (4) For two-stack queues, does the question ask for a single worst-case operation or the amortized cost over a sequence? (5) In a linked-list trace, save next before overwriting it, and check both fast != NULL and fast->next != NULL before advancing fast by two. (6) Deleting the last node of a singly linked list is O(n) even with a tail pointer. (7) The Floyd meeting-point distance is a mod c, which differs from a once the tail is at least as long as the cycle.

PREVIOUS-YEAR QUESTIONS

13 questions from the CS and DA papers

Try each question first, then open the answer. We placed each question under a topic ourselves; the exam paper does not label topics.

See these papers in full: GATE CSE 2026 Set 1 · GATE CSE 2026 Set 2 · GATE CSE 2025 Set 2 · GATE CSE 2024 Set 2 · GATE CSE 2023 · GATE CSE 2022 · GATE CSE 2020 · GATE CSE 2018 · GATE DA 2025 · GATE DA 2024

GATE 2026 CS1 Q.39

GATE 2026 · CS1Q.39 · 2 marks · MCQ

Consider the following code snippet in C language that computes the number of nodes in a non-empty singly linked list pointed to by the pointer variable head.

struct node{
  int elt;
  struct node *next;
};

int getListSize (struct node *head)
{
  if( E1 ) return 1;
  return E2;
}

Which one of the following options gives the correct replacements for the expressions E1 and E2?

  1. (A)

    E1: head == NULL
    E2: 1 + getListSize(head)

  2. (B)

    E1: head->next == NULL
    E2: 1 + getListSize(head->next)

  3. (C)

    E1: head == NULL
    E2: 1 + getListSize(head->next)

  4. (D)

    E1: head->next == NULL
    E2: 1 + getListSize(head)

Answer and solution
See the question in the paper
GATE 2026 CS1 Q.39: answer and solution

GATE 2026 CS2 Q.50

GATE 2026 · CS2Q.50 · 2 marks · MSQ

Consider a stack S and a queue Q. Both of them are initially empty and have the capacity to store ten elements each. The elements 1, 2, 3, 4, and 5 arrive one by one, in that order. When an element arrives, it is assigned either to S (pushed on S) or to Q (enqueued to Q). Once all the five elements are stored, the output is generated in two steps. First, stack S is emptied by popping all elements. Then queue Q is emptied by dequeueing all elements. The output obtained by following this process is 4 3 1 2 5.

Given the output, the objective is to predict whether an element was assigned to S or Q.

Which of the following options is/are possible valid assignment(s) of the elements?

Note: In the options, the notation xS denotes that element x was assigned to S and yQ denotes that element y was assigned to Q.

  1. (A)

    1S, 2Q, 3S, 4S, 5Q

  2. (B)

    1Q, 2Q, 3S, 4S, 5Q

  3. (C)

    1Q, 2Q, 3Q, 4S, 5S

  4. (D)

    1S, 2S, 3S, 4Q, 5Q

Answer and solution
See the question in the paper
GATE 2026 CS2 Q.50: answer and solution

GATE 2025 CS2 Q.45

GATE 2025 · CS2Q.45 · 2 marks · MSQ

Consider a stack data structure into which we can PUSH and POP records. Assume that each record pushed in the stack has a positive integer key and that all keys are distinct.

We wish to augment the stack data structure with an time MIN operation that returns a pointer to the record with smallest key present in the stack

1) without deleting the corresponding record, and
2) without increasing the complexities of the standard stack operations.

Which one or more of the following approaches can achieve it?

  1. (A)

    Keep with every record in the stack, a pointer to the record with the smallest key below it.

  2. (B)

    Keep a pointer to the record with the smallest key in the stack.

  3. (C)

    Keep an auxiliary array in which the key values of the records in the stack are maintained in sorted order.

  4. (D)

    Keep a Min-Heap in which the key values of the records in the stack are maintained.

Answer and solution
See the question in the paper
GATE 2025 CS2 Q.45: answer and solution

GATE 2025 DA Q.64

GATE 2025 · DAQ.64 · 2 marks · NAT

Consider the following pseudocode.

Create empty stack S
Set x=0, flag=0, sum=0
Push x onto S
while (S is not empty){
   if (flag equals 0){
     Set x = x+1
     Push x onto S}
   if (x equals 8):
     Set flag=1
   if (flag equals 1){
     x = Pop(S)
     if (x is odd):
       Pop(S)
     Set sum = sum + x}
}
Output sum

The value of sum output by a program executing the above pseudocode is ______________ (Answer in integer)

Answer and solution
See the question in the paper
GATE 2025 DA Q.64: answer and solution

GATE 2024 CS2 Q.48

GATE 2024 · CS2Q.48 · 2 marks · MSQ

Let S1 and S2 be two stacks. S1 has capacity of 4 elements. S2 has capacity of 2 elements. S1 already has 4 elements: 100, 200, 300, and 400, whereas S2 is empty, as shown below.

Stack S1 (bottom to top): 100, 200, 300, 400 (Top)
Stack S2: empty (capacity 2)

Only the following three operations are available:

PushToS2: Pop the top element from S1 and push it on S2.
PushToS1: Pop the top element from S2 and push it on S1.
GenerateOutput: Pop the top element from S1 and output it to the user.

Note that the pop operation is not allowed on an empty stack and the push operation is not allowed on a full stack.

Which of the following output sequences can be generated by using the above operations?

GATE 2024 CS2 question 48: Two stack diagrams side by side.Tap to open full size
Figure from the GATE 2024 CS2 paper. It is part of the question.
Figure description

Two stack diagrams side by side. Left: Stack S1, drawn as a vertical box divided into 4 cells, bottom to top: 100, 200, 300, 400, with '400 (Top)' labeling the topmost cell, labeled 'Stack S1' below. Right: Stack S2, drawn as a vertical box with 2 empty cells (capacity 2), labeled 'Stack S2' below, currently empty.

  1. (A)

    100, 200, 400, 300

  2. (B)

    200, 300, 400, 100

  3. (C)

    400, 200, 100, 300

  4. (D)

    300, 200, 400, 100

Answer and solution
GATE 2024 CS2 Q.48: answer and solution

GATE 2024 DA Q.16

GATE 2024 · DAQ.16 · 1 mark · MCQ

Match the items in Column 1 with the items in Column 2 in the following table:

GATE 2024 DA question 16: A two-column table.Tap to open full size
Figure from the GATE 2024 DA paper. It is part of the question.
Figure description

A two-column table. Column 1: (p) First In First Out; (q) Lookup Operation; (r) Last In First Out. Column 2: (i) Stacks; (ii) Queues; (iii) Hash Tables.

  1. (A)

    (p) − (ii), (q) − (iii), (r) − (i)

  2. (B)

    (p) − (ii), (q) − (i), (r) − (iii)

  3. (C)

    (p) − (i), (q) − (ii), (r) − (iii)

  4. (D)

    (p) − (i), (q) − (iii), (r) − (ii)

Answer and solution
GATE 2024 DA Q.16: answer and solution

GATE 2024 DA Q.32

GATE 2024 · DAQ.32 · 1 mark · NAT

The fundamental operations in a double-ended queue D are:

insertFirst(e) – Insert a new element e at the beginning of D.
insertLast(e) – Insert a new element e at the end of D.
removeFirst() – Remove and return the first element of D.
removeLast() – Remove and return the last element of D.

In an empty double-ended queue, the following operations are performed:

insertFirst(10)
insertLast(32)
a ← removeFirst()
insertLast(28)
insertLast(17)
a ← removeFirst()
a ← removeLast()

The value of a is ______.

Answer and solution
See the question in the paper
GATE 2024 DA Q.32: answer and solution

GATE 2023 CS Q.13

GATE 2023 · CSQ.13 · 1 mark · MCQ

Let SLLdel be a function that deletes a node in a singly-linked list given a pointer to the node and a pointer to the head of the list. Similarly, let DLLdel be another function that deletes a node in a doubly-linked list given a pointer to the node and a pointer to the head of the list.

Let denote the number of nodes in each of the linked lists. Which one of the following choices is TRUE about the worst-case time complexity of SLLdel and DLLdel?

  1. (A)

    SLLdel is and DLLdel is

  2. (B)

    Both SLLdel and DLLdel are

  3. (C)

    Both SLLdel and DLLdel are

  4. (D)

    SLLdel is and DLLdel is

Answer and solution
See the question in the paper
GATE 2023 CS Q.13: answer and solution

GATE 2023 CS Q.59

GATE 2023 · CSQ.59 · 2 marks · NAT

Consider a sequence of elements , , , , , and . The following operations are performed on a stack and a queue , both of which are initially empty.

I: push the elements of from to in that order into .

II: enqueue the elements of from to in that order into .

III: pop an element from .

IV: dequeue an element from .

V: pop an element from .

VI: dequeue an element from .

VII: dequeue an element from and push the same element into .

VIII: Repeat operation VII three times.

IX: pop an element from .

X: pop an element from .

The top element of after executing the above operations is ____ (answer as an integer).

Answer and solution
See the question in the paper
GATE 2023 CS Q.59: answer and solution

GATE 2022 CS Q.15

GATE 2022 · CSQ.15 · 1 mark · MCQ

Consider the problem of reversing a singly linked list. To take an example, given the linked list below,

head → [a|•]→ [b|•]→ [c|•]→ [d|•]→ [e|•]→ (null, shown as ground symbol)

the reversed linked list should look like

head → [e|•]→ [d|•]→ [c|•]→ [b|•]→ [a|•]→ (null, shown as ground symbol)

Which one of the following statements is TRUE about the time complexity of algorithms that solve the above problem in space?

GATE 2022 CS question 15: Two horizontal singly linked list diagrams, each a chain of 5 boxes.Tap to open full size
Figure from the GATE 2022 CS paper. It is part of the question.
Figure description

Two horizontal singly linked list diagrams, each a chain of 5 boxes. Each box is drawn as a two-cell node: left cell holds a data value, right cell holds a pointer (drawn as a small vertical bar with an arrow leaving it to the next node). Top diagram (original list): 'head' with an arrow into node containing 'a', arrow to node 'b', arrow to node 'c', arrow to node 'd', arrow to node 'e', and the last node's pointer cell points to a ground/earth symbol (⏚) denoting NULL. Bottom diagram (reversed list): identical structure but with values in order 'head' → e → d → c → b → a → NULL (ground symbol). This just illustrates that the list a-b-c-d-e becomes e-d-c-b-a after reversal.

  1. (A)

    The best algorithm for the problem takes time in the worst case.

  2. (B)

    The best algorithm for the problem takes time in the worst case.

  3. (C)

    The best algorithm for the problem takes time in the worst case.

  4. (D)

    It is not possible to reverse a singly linked list in space.

Answer and solution
GATE 2022 CS Q.15: answer and solution

GATE 2022 CS Q.62

GATE 2022 · CSQ.62 · 2 marks · NAT

Consider the queues containing four elements and containing none (shown as the Initial State in the figure). The only operations allowed on these two queues are Enqueue(Q, element) and Dequeue(Q). The minimum number of Enqueue operations on required to place the elements of in in reverse order (shown as the Final State in the figure) without using any additional storage is ______.

GATE 2022 CS question 62: Two labeled box diagrams side by side.Tap to open full size
Figure from the GATE 2022 CS paper. It is part of the question.
Figure description

Two labeled box diagrams side by side. Left diagram, titled 'Initial State': an arrow labeled 'Head' points into the front of queue Q1, which is drawn as four cells left to right containing 1, 2, 3, 4 (so 1 is at the head/front); below it, queue Q2 is drawn as four empty cells, with an arrow labeled 'Head' pointing into its front (leftmost) cell from below. Right diagram, titled 'Final State': same layout — Q1 is drawn as four empty cells with a 'Head' arrow into its front; Q2 is drawn as four cells containing 4, 3, 2, 1 left to right (so 4 is at the head/front), with a 'Head' arrow into its front cell from below.

Answer and solution
GATE 2022 CS Q.62: answer and solution

GATE 2018 CS Q.3

GATE 2018 · CSQ.3 · 1 mark · MCQ

A queue is implemented using a non-circular singly linked list. The queue has a head pointer and a tail pointer, as shown in the figure. Let denote the number of nodes in the queue. Let enqueue be implemented by inserting a new node at the head, and dequeue be implemented by deletion of a node from the tail.

[Figure: a singly linked list of nodes drawn left to right, each node a two-cell box with a right-pointing arrow to the next node. The first (leftmost) node is labelled by an upward arrow from the word "head". A row of dots indicates further nodes in between. The last (rightmost) node is labelled by an upward arrow from the word "tail", and its next-pointer cell points to a ground symbol (null terminator).]

Which one of the following is the time complexity of the most time-efficient implementation of enqueue and dequeue, respectively, for this data structure?

GATE 2018 CS question 3: A non-circular singly linked list drawn left to right: each node is a box split into a data cell and a next-pointer cell…Tap to open full size
Figure from the GATE 2018 CS paper. It is part of the question.
Figure description

A non-circular singly linked list drawn left to right: each node is a box split into a data cell and a next-pointer cell, with an arrow from the pointer cell to the next node's box. The head pointer points (upward arrow) to the first node. A row of dots between the second node and the last node indicates additional nodes. The tail pointer points (upward arrow) to the last node, whose next-pointer cell points to a ground/earth symbol representing NULL — confirming the list is singly linked (no backward links) and non-circular.

  1. (A)

  2. (B)

  3. (C)

  4. (D)

Answer and solution
GATE 2018 CS Q.3: answer and solution

PRACTICE

6 questions to test yourself

PRACTICE 11 mark · MCQ

Convert the infix expression a + b * c - (d / e ^ f) to postfix. Assume the usual precedence ^ > *,/ > +,-, with ^ (exponentiation) right-associative and *, /, +, - left-associative. Which of the following is the correct postfix form?

  1. (A)

    a b c * + d e f ^ / -

  2. (B)

    a b c * + d e f / ^ -

  3. (C)

    a b * c + d e f ^ / -

  4. (D)

    a b c + * d e f ^ / -

Answer and solution

Answer: (A)

  1. Inside the parentheses, ^ binds tighter than /, so d / (e ^ f) becomes d e f ^ /.

  2. b c becomes b c , and a + (b c) becomes a b c +.

  3. + and - have equal precedence and are left-associative, so the expression is (a + b*c) - (d / e^f), which becomes a b c * + d e f ^ / -.

  4. This is option A. B applies / before ^, C computes (a*b)+c, and D computes (b+c)*a.

PRACTICE 21 mark · NAT

A circular queue is stored in an array of capacity 6 (indices 0 to 5). It keeps a front index, a rear index and a count, and no slot is sacrificed. Start from empty (front = 0, rear = -1, count = 0). Enqueue A, B, C, D, E; each enqueue sets rear = (rear + 1) % 6. Then dequeue twice; each dequeue sets front = (front + 1) % 6, removing A and then B. Then enqueue F, G, H. The queue is now full (count = 6). What is the value of the front index?

Answer and solution

Answer:

  1. Enqueuing A, B, C, D, E sets rear to 0, 1, 2, 3, 4 in turn. front stays 0 and count becomes 5.

  2. The first dequeue removes A (index 0) and sets front = (0 + 1) % 6 = 1. The second removes B (index 1) and sets front = (1 + 1) % 6 = 2. count is now 3.

  3. Enqueue F: rear = (4 + 1) % 6 = 5. Enqueue G: rear = (5 + 1) % 6 = 0, reusing A's old slot. Enqueue H: rear = (0 + 1) % 6 = 1, reusing B's old slot. count = 6, so the queue is full.

  4. Enqueues never move front, so front = 2. It points at C, the oldest element still in the queue.

PRACTICE 32 marks · MSQ

Elements 1, 2, 3, 4, 5 are pushed onto an initially empty stack strictly in that order, and pops may be interleaved with the remaining pushes at any point. Which of the following output sequences can be produced? Use the standard feasibility test: push the next unpushed input whenever the stack is empty or its top is not the next required output; if no inputs remain and the top still does not match, the sequence is infeasible.

  1. (A)

    3, 2, 4, 1, 5

  2. (B)

    5, 4, 3, 2, 1

  3. (C)

    4, 3, 5, 1, 2

  4. (D)

    2, 4, 1, 3, 5

Answer and solution

Answer: (A), (B)

  1. (A) 3, 2, 4, 1, 5: push 1, 2, 3 and pop 3; pop 2; push 4 and pop 4; pop 1; push 5 and pop 5. Every target is produced, so A is achievable.

  2. (B) 5, 4, 3, 2, 1: push 1 to 5, then pop 5, 4, 3, 2, 1. A fully decreasing output is always achievable, so B is achievable.

  3. (C) 4, 3, 5, 1, 2: push 1 to 4 and pop 4; pop 3 (the stack is now 1, 2 with 2 on top); push 5 and pop 5. The next target is 1, but the top is 2 and no inputs remain, so C is infeasible.

  4. (D) 2, 4, 1, 3, 5: push 1, 2 and pop 2 (stack: 1); push 3, 4 and pop 4 (stack: 1, 3). The next target is 1 but the top is 3, so push the last input 5 (stack: 1, 3, 5). The top is still not 1 and no inputs remain, so D is infeasible: 1 is buried under 3.

  5. Cross-check with the 3-1-2 rule: C contains 4, 1, 2 and D contains 4, 1, 3 (a larger value, then a smaller one, then a value in between), so both are unachievable. A and B contain no such pattern.

  6. Answer: A and B.

PRACTICE 42 marks · MCQ

A singly linked list holds the values 5, 3, 8, 8, 2, 9, 1, in that order from head to tail. Consider:

int mystery(struct Node *head) {
    int count = 0;
    struct Node *p = head;
    while (p != NULL && p->next != NULL) {
        if (p->data > p->next->data)
            count++;
        p = p->next;
    }
    return count;
}

What value does mystery(head) return for this list?

  1. (A)

    2

  2. (B)

    3

  3. (C)

    4

  4. (D)

    5

Answer and solution

Answer: (B)

  1. The function walks every adjacent pair and counts the positions where a node's data is strictly greater than the next node's data.

  2. The pairs in order: (5, 3) counts; (3, 8) does not; (8, 8) does not (not strictly greater); (8, 2) counts; (2, 9) does not; (9, 1) counts.

  3. That is 3 counted pairs, so the function returns 3 (option B).

PRACTICE 52 marks · NAT

A singly linked list contains a cycle. Starting at the head, following next 8 times reaches the first node of the cycle (a = 8). The cycle contains 6 nodes (c = 6). Pointers slow and fast both start at the head. In each iteration slow moves 1 link and fast moves 2 links, and then the two are compared, as in hasCycle. After they first meet, what is the smallest number of links that must be followed forward from the meeting node to reach the first node of the cycle?

Answer and solution

Answer:

  1. Label each node by its distance from the head. Nodes 0 to 7 form the tail; node 8 is the cycle start, and a node at distance p >= 8 is (p - 8) mod 6 links past the cycle start.

  2. After t iterations, slow has moved t links and fast 2t links. While t < 8, slow is still in the tail, where fast is never on the same node, so they cannot meet.

  3. For t >= 8 they meet when (t - 8) mod 6 = (2t - 8) mod 6, that is when t is a multiple of 6. The smallest such t >= 8 is t = 12.

  4. The meeting node is (12 - 8) mod 6 = 4 links past the cycle start, so reaching the start takes 6 - 4 = 2 more links.

  5. Check with the formula: a mod c = 8 mod 6 = 2. Following a = 8 links from the meeting node also reaches the start, but only after passing it once (2 + 6), so 8 is not the smallest distance. The trap answer is 8; the correct answer is 2.

PRACTICE 61 mark · NAT

In C, int A[10][20]; is stored row-major with 4-byte ints, and indices start at 0. The base address of A (the address of A[0][0]) is 1000 (decimal). What is the address of A[5][7] (decimal)?

Answer and solution

Answer:

  1. Row-major, 0-indexed: Addr(A[i][j]) = Base + (i*cols + j)*w, with cols = 20 and w = 4.

  2. Elements before A[5][7]: 5*20 + 7 = 107.

  3. Address = 1000 + 107*4 = 1000 + 428 = 1428.

OFFICIAL GATE 2027 SYLLABUS WORDING

Copied from the GATE 2027 syllabus; see all 2027 syllabi.

GATE CS

Arrays, stacks, queues, linked lists

GATE DA

stacks, queues, linked lists

Preparing in Kolkata? IAE Academy's course for GATE CSE or GATE DA.