Browse papers
A

Section A: Long Answer Questions

Attempt all / any as specified.

4 questions
1long12 marks

(a) Define a stack and list its basic operations (PUSH, POP, PEEK) along with the overflow and underflow conditions. Write an algorithm to implement these operations using a one-dimensional array. (6)

(b) Convert the following infix expression into its equivalent postfix expression using a stack, showing the stack and output at each step:

A + ( B * C - ( D / E ^ F ) * G ) * H

Then explain how the resulting postfix expression is evaluated using a stack. (6)

(a) Stack: definition, operations and array implementation

A stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle: the element inserted last is the one removed first. All insertions and deletions take place at one end called the top.

Basic operations

  • PUSH(x) — insert element x at the top of the stack.
  • POP() — remove and return the top element.
  • PEEK() (or TOP) — return the top element without removing it.

Overflow and underflow (array of size MAX, top initialised to -1)

  • Overflow: attempting to PUSH when top == MAX - 1 (stack full).
  • Underflow: attempting to POP/PEEK when top == -1 (stack empty).
#define MAX 100
int stack[MAX];
int top = -1;

void push(int x) {
    if (top == MAX - 1)            // overflow check
        printf("Stack Overflow\n");
    else
        stack[++top] = x;
}

int pop() {
    if (top == -1) {              // underflow check
        printf("Stack Underflow\n");
        return -1;
    }
    return stack[top--];
}

int peek() {
    if (top == -1) {
        printf("Stack Empty\n");
        return -1;
    }
    return stack[top];
}

(b) Infix to postfix conversion

Expression: A + ( B * C - ( D / E ^ F ) * G ) * H

Precedence: ^ (highest, right-associative) > * / > + -. We scan left to right; operands go to output, operators are managed on the stack.

SymbolStack (bottom→top)Output
A(empty)A
++A
(+ (A
B+ (A B
*+ ( *A B
C+ ( *A B C
-+ ( -A B C *
(+ ( - (A B C *
D+ ( - (A B C * D
/+ ( - ( /A B C * D
E+ ( - ( /A B C * D E
^+ ( - ( / ^A B C * D E
F+ ( - ( / ^A B C * D E F
)+ ( -A B C * D E F ^ /
*+ ( - *A B C * D E F ^ /
G+ ( - *A B C * D E F ^ / G
)+A B C * D E F ^ / G * -
*+ *A B C * D E F ^ / G * -
H+ *A B C * D E F ^ / G * - H
end(empty)A B C * D E F ^ / G * - H * +

Postfix: A B C * D E F ^ / G * - H * +

Evaluation using a stack: Scan the postfix expression left to right. Push every operand onto the stack. On meeting an operator, pop the top two operands (the first popped is the right operand, the second is the left), apply the operator, and push the result back. After the whole string is scanned, the single value remaining on the stack is the final result.

stacks-and-queuesrecursion
2long12 marks

(a) Define a Binary Search Tree (BST). Starting from an empty tree, insert the following keys one by one and draw the resulting BST: 45, 30, 60, 25, 40, 55, 70, 35. (5)

(b) Write the inorder, preorder and postorder traversal sequences of the BST obtained in part (a). (3)

(c) From the BST in part (a), delete node 30 and then node 60. Draw the tree after each deletion and clearly explain the rule you applied for deleting a node that has two children. (4)

(a) Binary Search Tree and insertion

A Binary Search Tree (BST) is a binary tree in which, for every node, all keys in its left subtree are smaller than the node's key and all keys in its right subtree are greater (no duplicates). This ordering allows search, insertion and deletion in O(h)O(h) time, where hh is the height.

Inserting 45, 30, 60, 25, 40, 55, 70, 35 (45 is the root; each key goes left if smaller, right if larger):

              45
            /    \
          30      60
         /  \    /  \
        25  40  55  70
            /
           35

(b) Traversals of the BST

  • Inorder (Left, Root, Right) — gives sorted order: 25, 30, 35, 40, 45, 55, 60, 70
  • Preorder (Root, Left, Right): 45, 30, 25, 40, 35, 60, 55, 70
  • Postorder (Left, Right, Root): 25, 35, 40, 30, 55, 70, 60, 45

(c) Deletions

Rule for deleting a node with two children: replace the node's key with its inorder successor (the smallest key in its right subtree) — or equivalently the inorder predecessor — then delete that successor node, which has at most one child.

Delete 30 (it has two children: 25 and 40). Inorder successor of 30 is 35 (smallest in the right subtree rooted at 40). Replace 30 with 35 and remove the original 35:

              45
            /    \
          35      60
         /  \    /  \
        25  40  55  70

Delete 60 (two children: 55 and 70). Inorder successor is 70 (smallest in its right subtree). Replace 60 with 70 and remove the leaf 70:

              45
            /    \
          35      70
         /  \    /
        25  40  55
trees-and-bst
3long12 marks

(a) Differentiate between the adjacency matrix and adjacency list representations of a graph, commenting on their space requirements. (4)

(b) Write the algorithms for Depth First Search (DFS) and Breadth First Search (BFS) traversal of a graph, mentioning the auxiliary data structure each one uses. (4)

(c) For the graph given below, show the order in which vertices are visited using both DFS and BFS, starting from vertex A. Assume adjacent vertices are visited in alphabetical order.

A - B,  A - C
B - D,  B - E
C - F
E - F,  E - G

(4)

(a) Adjacency matrix vs adjacency list

For a graph with VV vertices and EE edges:

FeatureAdjacency MatrixAdjacency List
StructureV×VV \times V 2-D array; M[i][j]=1 if edge existsArray of VV lists; list i holds neighbours of i
SpaceO(V2)O(V^2) regardless of edgesO(V+E)O(V + E)
Best forDense graphsSparse graphs
Check edge (u,v)O(1)O(1)O(deg(u))O(\deg(u))
List all neighbours of uO(V)O(V)O(deg(u))O(\deg(u))

A matrix wastes space on sparse graphs because it stores a slot for every possible edge; a list stores only existing edges, so it is far more space-efficient when EV2E \ll V^2.

(b) DFS and BFS algorithms

DFS uses a stack (explicitly, or implicitly via recursion):

DFS(G, s):
    mark all vertices unvisited
    push s onto stack
    while stack not empty:
        v = pop()
        if v not visited:
            visit v; mark visited
            push all unvisited neighbours of v

BFS uses a queue:

BFS(G, s):
    mark all vertices unvisited
    visit s; mark visited; enqueue s
    while queue not empty:
        v = dequeue()
        for each unvisited neighbour w of v:
            visit w; mark visited; enqueue w

(c) Traversal starting from A (neighbours in alphabetical order)

Adjacency: A→B,C B→D,E C→F E→F,G

  • DFS (A): start A → B → D (dead end, backtrack) → E → F (dead end) → G (dead end), backtrack to A → C (its neighbour F already visited). Visiting order: A, B, D, E, F, G, C.
  • BFS (A): level by level — A | B, C | D, E, F | G → A, B, C, D, E, F, G
graphs-and-traversals
4long12 marks

(a) Write the algorithm for Quick Sort and explain the working of the partition step with the role of the pivot element. (6)

(b) Sort the following list in ascending order using Quick Sort, choosing the first element as the pivot, and show the array after each partitioning pass:

38, 27, 43, 3, 9, 82, 10

(4)

(c) Derive the best-case and worst-case time complexity of Quick Sort and state when the worst case occurs. (2)

(a) Quick Sort algorithm and partitioning

Quick Sort is a divide-and-conquer sorting algorithm. It picks a pivot, partitions the array so that all elements smaller than the pivot lie to its left and all larger to its right (the pivot reaches its final sorted position), then recursively sorts the two partitions.

QUICKSORT(A, low, high):
    if low < high:
        p = PARTITION(A, low, high)   // pivot index
        QUICKSORT(A, low, p - 1)
        QUICKSORT(A, p + 1, high)

PARTITION(A, low, high):       // first element as pivot
    pivot = A[low]
    i = low + 1; j = high
    while true:
        while i <= j and A[i] <= pivot: i++
        while i <= j and A[j] >  pivot: j--
        if i < j: swap(A[i], A[j])
        else: break
    swap(A[low], A[j])         // place pivot in correct slot
    return j

Role of the pivot: the pivot is the reference element. The partition step rearranges the array around it so the pivot lands in its correct final position, splitting the problem into two independent smaller sub-arrays.

(b) Sorting 38, 27, 43, 3, 9, 82, 10 (first element as pivot)

Pass 1 — pivot = 38: elements ≤38 to the left, >38 to the right.
Result: [27, 3, 9, 10] 38 [82, 43]27 3 9 10 38 82 43

Left sub-array 27, 3, 9, 10 — pivot = 27:
[3, 9, 10] 273 9 10 27

  • 3, 9, 10 pivot 3 → 3 [9, 10]; 9,10 pivot 9 → 9 10. Left part sorted: 3 9 10 27.

Right sub-array 82, 43 — pivot = 82:
[43] 8243 82

Final sorted array: 3, 9, 10, 27, 38, 43, 82

(c) Time complexity

  • Best case — pivot splits the array into two nearly equal halves: T(n)=2T(n/2)+O(n)=O(nlogn)T(n) = 2T(n/2) + O(n) = O(n \log n).
  • Worst case — pivot is always the smallest or largest element, giving partitions of sizes 00 and n1n-1: T(n)=T(n1)+O(n)=O(n2)T(n) = T(n-1) + O(n) = O(n^2).
  • The worst case occurs when the array is already sorted (or reverse-sorted) and the first/last element is chosen as pivot.
sorting-algorithmsalgorithm-complexity
B

Section B: Short Answer Questions

Attempt all / any as specified.

7 questions
5short8 marks

(a) Differentiate between a singly linked list and a doubly linked list with neat diagrams. (3)

(b) Write an algorithm to insert a new node at the beginning and to delete a node from the end of a singly linked list. (5)

(a) Singly vs doubly linked list

FeatureSingly Linked ListDoubly Linked List
Pointers per nodeone (next)two (prev, next)
Traversalforward onlyboth directions
Memoryless (1 pointer)more (2 pointers)
Delete given nodeneeds previous nodedirect via prev

Singly: [data|next] -> [data|next] -> [data|NULL]

Doubly: NULL <- [prev|data|next] <-> [prev|data|next] -> NULL

(b) Algorithms

Insert at beginning

INSERT_FRONT(head, x):
    new = allocate node
    new.data = x
    new.next = head
    head = new          // new node becomes head
    return head

Delete from end

DELETE_END(head):
    if head == NULL: return NULL          // empty
    if head.next == NULL:                 // single node
        free(head); return NULL
    temp = head
    while temp.next.next != NULL:          // stop at 2nd-last
        temp = temp.next
    free(temp.next)
    temp.next = NULL
    return head
linked-lists
6short8 marks

(a) What is a circular queue? Explain how it overcomes the limitation of a linear queue implemented using an array. (4)

(b) For a circular queue of size 5, show the contents of the array, FRONT and REAR after the following sequence of operations: enqueue(10), enqueue(20), enqueue(30), dequeue(), enqueue(40), enqueue(50), enqueue(60). (4)

(a) Circular queue

A circular queue is a linear queue in which the last position is logically connected back to the first position, forming a circle. Indices wrap around using modulo arithmetic: REAR = (REAR + 1) % SIZE and FRONT = (FRONT + 1) % SIZE.

Limitation of a linear array queue it solves: in a simple linear queue, when REAR reaches the last index the queue is treated as full even if cells at the front were freed by dequeues — this is false overflow and wastes space. A circular queue reuses those vacated front cells by wrapping REAR around, so space is fully utilised without shifting elements.

(b) Trace for circular queue of size 5 (indices 0–4)

Start: FRONT = -1, REAR = -1 (empty).

OperationArray [0..4]FRONTREAR
enqueue(10)10 . . . .00
enqueue(20)10 20 . . .01
enqueue(30)10 20 30 . .02
dequeue() (removes 10). 20 30 . .12
enqueue(40). 20 30 40 .13
enqueue(50). 20 30 40 5014
enqueue(60)60 20 30 40 5010

Final: array = 60, 20, 30, 40, 50, FRONT = 1, REAR = 0 (REAR wrapped around to index 0). The queue is now full.

stacks-and-queues
7short8 marks

(a) Define recursion and explain the difference between a recursive and an iterative solution with respect to memory usage. (3)

(b) Write a recursive function to solve the Tower of Hanoi problem for n disks and determine the total number of moves required for n = 4 disks. (5)

(a) Recursion

Recursion is a technique in which a function calls itself (directly or indirectly) to solve a problem by reducing it to smaller instances of the same problem, with a base case that stops the recursion.

Memory usage — recursive vs iterative: a recursive solution uses the call stack: each pending call adds a stack frame (storing parameters, local variables, return address), so memory grows with the recursion depth, O(depth)O(\text{depth}) extra space, and deep recursion may cause stack overflow. An iterative solution uses a loop with a fixed set of variables, typically requiring only O(1)O(1) extra space, making it more memory-efficient.

(b) Tower of Hanoi

void hanoi(int n, char src, char aux, char dst) {
    if (n == 1) {
        printf("Move disk 1 from %c to %c\n", src, dst);
        return;
    }
    hanoi(n - 1, src, dst, aux);   // move top n-1 to auxiliary
    printf("Move disk %d from %c to %c\n", n, src, dst);
    hanoi(n - 1, aux, src, dst);   // move n-1 from aux to dest
}

Number of moves: the recurrence is T(n)=2T(n1)+1T(n) = 2T(n-1) + 1, T(1)=1T(1)=1, giving T(n)=2n1T(n) = 2^n - 1.

For n=4n = 4: T(4)=241=161=15T(4) = 2^4 - 1 = 16 - 1 = \mathbf{15} moves.

recursion
8short8 marks

(a) Define a hash function and explain what is meant by a collision in hashing. (3)

(b) Insert the keys 23, 43, 13, 27, 33 into a hash table of size 10 using the hash function h(k) = k mod 10, resolving collisions by linear probing. Show the final table. (5)

(a) Hash function and collision

A hash function h(k)h(k) maps a key kk to an index in a hash table (typically 00 to m1m-1), ideally distributing keys uniformly so that lookup, insertion and deletion take average O(1)O(1) time.

A collision occurs when two distinct keys k1k2k_1 \ne k_2 hash to the same index, i.e. h(k1)=h(k2)h(k_1) = h(k_2). Collisions are unavoidable when the number of keys exceeds the table size, and must be handled by a collision-resolution method (e.g. linear probing, chaining).

(b) Insert 23, 43, 13, 27, 33 with h(k)=k mod 10, linear probing

Keyh(k)Probe sequenceFinal index
2333 free3
4333 taken → 4 free4
1333,4 taken → 5 free5
2777 free7
3333,4,5 taken → 6 free6

Final hash table:

Index0123456789
Key---2343133327--
searching-and-hashing
9short8 marks

(a) Write the algorithm for binary search and state the precondition that the input must satisfy. (4)

(b) Trace binary search to locate the key 23 in the sorted array [4, 8, 15, 16, 23, 42, 50], showing the values of low, high and mid at each step, and derive its time complexity. (4)

(a) Binary search algorithm

Precondition: the input array must be sorted (here, in ascending order).

BINARY_SEARCH(A, n, key):
    low = 0; high = n - 1
    while low <= high:
        mid = (low + high) / 2          // integer division
        if A[mid] == key: return mid     // found
        else if A[mid] < key: low = mid + 1
        else: high = mid - 1
    return -1                            // not found

(b) Trace: find 23 in [4, 8, 15, 16, 23, 42, 50] (indices 0–6)

SteplowhighmidA[mid]Action
10631616 < 23 → low = 4
24654242 > 23 → high = 4
344423found at index 4

Key 23 found at index 4 in 3 comparisons.

Time complexity: each step halves the search interval, so the number of comparisons is at most log2n\log_2 n. Hence binary search runs in O(logn)O(\log n) in the worst and average case, and O(1)O(1) in the best case (key at the first mid).

searching-and-hashingalgorithm-complexity
10short8 marks

(a) Define Big-O, Big-Omega (Ω) and Big-Theta (Θ) asymptotic notations. (4)

(b) Determine the time complexity of the following code fragment in terms of Big-O notation and justify your answer:

for (i = 1; i <= n; i++) {
    for (j = 1; j <= n; j = j * 2) {
        printf("%d", i + j);
    }
}

(4)

(a) Asymptotic notations

For functions f(n)f(n) and g(n)g(n):

  • Big-O (upper bound): f(n)=O(g(n))f(n) = O(g(n)) if there exist constants c>0c>0 and n0n_0 such that 0f(n)cg(n)0 \le f(n) \le c\,g(n) for all nn0n \ge n_0. Describes the worst-case / maximum growth rate.
  • Big-Omega (Ω\Omega, lower bound): f(n)=Ω(g(n))f(n) = \Omega(g(n)) if there exist c>0,n0c>0, n_0 such that 0cg(n)f(n)0 \le c\,g(n) \le f(n) for all nn0n \ge n_0. Describes the minimum growth rate.
  • Big-Theta (Θ\Theta, tight bound): f(n)=Θ(g(n))f(n) = \Theta(g(n)) if there exist c1,c2>0,n0c_1, c_2 > 0, n_0 such that c1g(n)f(n)c2g(n)c_1 g(n) \le f(n) \le c_2 g(n) for all nn0n \ge n_0, i.e. ff is both O(g)O(g) and Ω(g)\Omega(g).

(b) Complexity of the code

for (i = 1; i <= n; i++)            // outer: runs n times
    for (j = 1; j <= n; j = j * 2)  // inner: j doubles each time
        printf("%d", i + j);
  • The outer loop runs nn times.
  • The inner loop multiplies j by 2 each iteration (1,2,4,8,1, 2, 4, 8, \ldots), so it executes about log2n+1=O(logn)\lfloor \log_2 n \rfloor + 1 = O(\log n) times, independent of i.

Total work =n×log2n= n \times \log_2 n.

Time complexity = O(nlogn)O(n \log n).

algorithm-complexity
11short8 marks

(a) Define a heap and differentiate between a max-heap and a min-heap. (3)

(b) Build a max-heap from the following list of elements by successive insertion and draw the final heap, then show the array after performing one delete-max operation:

12, 19, 16, 1, 4, 7

(5)

(a) Heap, max-heap and min-heap

A heap is a complete binary tree (all levels full except possibly the last, which fills left to right) that satisfies the heap property at every node. It is usually stored in an array, where for node at index i the children are at 2i+1 and 2i+2.

  • Max-heap: every parent is its children, so the maximum element is at the root.
  • Min-heap: every parent is its children, so the minimum element is at the root.

(b) Build max-heap from 12, 19, 16, 1, 4, 7 by successive insertion

Insert each element at the end and sift up (swap with parent while larger):

  • Insert 12: 12
  • Insert 19: 19>12 → swap → 19, 12
  • Insert 16: 16<19 → 19, 12, 16
  • Insert 1: 19, 12, 16, 1
  • Insert 4: 19, 12, 16, 1, 4
  • Insert 7: 7<16 → 19, 12, 16, 1, 4, 7

Final max-heap array: 19, 12, 16, 1, 4, 7

            19
          /    \
        12      16
       /  \    /
      1    4  7

One delete-max operation: remove the root (19), move the last element (7) to the root, then sift down.

  • After moving 7 to root: 7, 12, 16, 1, 4
  • Children of 7 are 12 and 16; largest is 16 → swap 7 and 16: 16, 12, 7, 1, 4
  • 7 now a leaf → done.

Array after delete-max: 16, 12, 7, 1, 4

           16
         /    \
       12      7
      /  \
     1    4
trees-and-bstsorting-algorithms

Frequently asked questions

Where can I find the BE Computer Engineering (IOE, TU) Data Structure and Algorithm (IOE, CT 552) question paper 2078?
The full BE Computer Engineering (IOE, TU) Data Structure and Algorithm (IOE, CT 552) 2078 (regular) question paper is available free on Kekkei. You can read every question online and attempt the paper under timed exam conditions.
Does the Data Structure and Algorithm (IOE, CT 552) 2078 paper come with solutions?
Yes. Every question on this Data Structure and Algorithm (IOE, CT 552) past paper includes a step-by-step solution, plus instant AI feedback when you attempt it on Kekkei.
How many marks is the BE Computer Engineering (IOE, TU) Data Structure and Algorithm (IOE, CT 552) 2078 paper?
The BE Computer Engineering (IOE, TU) Data Structure and Algorithm (IOE, CT 552) 2078 paper carries 80 full marks and is meant to be completed in 180 minutes, across 11 questions.
Is practising this Data Structure and Algorithm (IOE, CT 552) past paper free?
Yes — reading and attempting this Data Structure and Algorithm (IOE, CT 552) past paper on Kekkei is completely free.