Browse papers
A

Section A: Long Answer Questions

Attempt all / any as specified.

4 questions
1long15 marks

(a) Define a stack and a queue as abstract data types, clearly stating the operations and the access policy (LIFO vs FIFO) of each. (b) Write an algorithm to convert an infix expression to its equivalent postfix form using a stack, and trace your algorithm on the expression A + B * (C - D) / E. (c) Explain how a circular queue overcomes the limitation of a simple linear queue implemented in an array, and write the conditions used to detect a full and an empty circular queue.

(a) Stack and Queue as Abstract Data Types

Stack (LIFO — Last In, First Out): A stack is a linear ADT in which insertion and deletion both occur at the same end, called the top. The element inserted most recently is the first to be removed.

Operations:

  • push(x) — insert element x at the top
  • pop() — remove and return the top element
  • peek()/top() — return the top element without removing it
  • isEmpty() — test whether the stack is empty

Queue (FIFO — First In, First Out): A queue is a linear ADT in which insertion occurs at one end (rear) and deletion at the other end (front). The element inserted first is the first to be removed.

Operations:

  • enqueue(x) — insert element x at the rear
  • dequeue() — remove and return the front element
  • front() — return the front element without removing it
  • isEmpty() — test whether the queue is empty

(b) Infix to Postfix Conversion using a Stack

Algorithm:

Initialize an empty stack and an empty output string.
Scan the infix expression left to right:
  1. If the token is an operand, append it to output.
  2. If the token is '(', push it onto the stack.
  3. If the token is ')', pop and append operators until '(' is
     popped (discard the '(').
  4. If the token is an operator o1:
       while stack top is an operator o2 with
         precedence(o2) > precedence(o1), OR
         precedence(o2) == precedence(o1) and o1 is left-associative:
           pop o2 and append to output
       push o1.
After scanning, pop and append all remaining operators.

Precedence: *, / (high) > +, - (low); all are left-associative.

Trace on A + B * (C - D) / E:

TokenStackOutput
A(empty)A
++A
B+A B
*+ *A B
(+ * (A B
C+ * (A B C
-+ * ( -A B C
D+ * ( -A B C D
)+ *A B C D -
/+ /A B C D - *
E+ /A B C D - * E
end(empty)A B C D - * E / +

(Note: at /, * has equal precedence and is left-associative, so * is popped first; then / is pushed.)

Postfix result: A B C D - * E / +

(c) Circular Queue vs Linear Queue

In a simple linear array queue, front and rear only move forward. After repeated enqueue/dequeue operations, rear reaches the last index even though free cells exist at the beginning (vacated by dequeue). This false-full / wasted-space problem cannot be reused without shifting elements.

A circular queue treats the array as a ring: after the last index it wraps to index 0 using modulo arithmetic, so freed front cells are reused. Index update: rear = (rear + 1) % SIZE, front = (front + 1) % SIZE.

Conditions (using count, or the one-cell-gap method):

  • Empty: front == -1 (or count == 0).
  • Full: (rear + 1) % SIZE == front (one-cell-gap method), or count == SIZE.
stacksqueuesexpression-evaluation
2long15 marks

(a) Construct a Binary Search Tree (BST) by inserting the following keys in the given order: 45, 15, 79, 90, 10, 55, 12, 20, 50. Show the tree after each insertion. (b) Write the inorder, preorder and postorder traversal sequences of the resulting tree. (c) Describe, with the help of diagrams, the procedure to delete a node that has two children from a BST, and apply it to delete the node 45 from the tree you constructed.

(a) BST Construction by inserting 45, 15, 79, 90, 10, 55, 12, 20, 50

Insert each key by comparing with nodes from the root, going left if smaller and right if larger.

  1. Insert 45 → root 45.
  2. Insert 15 (<45) → left of 45.
  3. Insert 79 (>45) → right of 45.
  4. Insert 90 (>45,>79) → right of 79.
  5. Insert 10 (<45,<15) → left of 15.
  6. Insert 55 (>45,<79) → left of 79.
  7. Insert 12 (<45,<15,>10) → right of 10.
  8. Insert 20 (<45,>15) → right of 15.
  9. Insert 50 (>45,<79,<55) → left of 55.

Final tree:

            45
          /    \
        15      79
       /  \    /  \
      10   20 55   90
        \     /
        12   50

(b) Traversal Sequences

  • Inorder (Left, Root, Right): 10, 12, 15, 20, 45, 50, 55, 79, 90 (sorted order, as expected for a BST)
  • Preorder (Root, Left, Right): 45, 15, 10, 12, 20, 79, 55, 50, 90
  • Postorder (Left, Right, Root): 12, 10, 20, 15, 50, 55, 90, 79, 45

(c) Deleting a Node with Two Children

Procedure: When the node to delete has two children, replace its key with its inorder successor (the smallest key in its right subtree) — or equivalently its inorder predecessor — then delete that successor node (which has at most one child, so it is easy to remove).

Steps to delete 45 (root, two children):

  1. Right subtree of 45 is rooted at 79. Its leftmost (smallest) node is 50 → inorder successor.
  2. Replace key 45 with 50.
  3. Delete the original 50 node. It was the left child of 55 and has no children, so simply remove it.

Tree after deletion:

            50
          /    \
        15      79
       /  \    /  \
      10   20 55   90
        \
        12

The BST property is preserved: 50 is greater than all keys in the left subtree and smaller than all remaining keys in the right subtree.

binary-search-treetreestree-traversal
3long15 marks

(a) Differentiate between the adjacency matrix and adjacency list representations of a graph, comparing their space and time requirements. (b) Explain the Breadth First Search (BFS) and Depth First Search (DFS) traversal techniques, mentioning the auxiliary data structure used by each. (c) Apply Dijkstra's algorithm to find the shortest path from source vertex A to all other vertices in a weighted graph of your choice (at least 5 vertices), showing the contents of the distance and visited sets at each step.

(a) Adjacency Matrix vs Adjacency List

For a graph with V vertices and E edges:

AspectAdjacency MatrixAdjacency List
StructureV × V matrix, M[i][j]=1 if edge i–jArray of V lists, each holding neighbours
SpaceO(V2)O(V^2)O(V+E)O(V + E)
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))
Best forDense graphsSparse graphs

(b) BFS and DFS

Breadth First Search (BFS): Explores the graph level by level — visits the source, then all its neighbours, then their unvisited neighbours, and so on. It uses a queue (FIFO) as the auxiliary structure and finds shortest paths in terms of edge count in an unweighted graph. Time: O(V+E)O(V+E) with an adjacency list.

Depth First Search (DFS): Explores as far as possible along one branch before backtracking. It uses a stack (LIFO) — explicitly, or implicitly via recursion. Useful for cycle detection, topological sort, connected components. Time: O(V+E)O(V+E).

(c) Dijkstra's Algorithm

Consider this weighted graph (source A):

A-B = 4    A-C = 1
C-B = 2    C-D = 5
B-E = 3    D-E = 1

Edges: A–B(4), A–C(1), C–B(2), C–D(5), B–E(3), D–E(1). Vertices: A,B,C,D,E.

Maintain a distance set dist[] (initially 0 for A, ∞ for others) and a visited set. Repeatedly pick the unvisited vertex with smallest distance and relax its edges.

StepPickeddist[A]dist[B]dist[C]dist[D]dist[E]Visited
init0{}
1A041{A}
2C0316{A,C}
3B03166{A,C,B}
4E03166{A,C,B,E}
5D03166{A,C,B,E,D}

At step 2, C relaxes B: 1+2=3 < 4. At step 3, B relaxes E: 3+3=6. At step 5, D relaxes E: 6+1=7 > 6, no change.

Final shortest distances from A: A=0, B=3 (A→C→B), C=1 (A→C), D=6 (A→C→D), E=6 (A→C→B→E).

graphsgraph-traversalshortest-path
4long15 marks

(a) Explain the working principle of Quick Sort with a suitable example, clearly describing the partitioning step. (b) Sort the array [38, 27, 43, 3, 9, 82, 10] using Merge Sort and show every level of division and merging. (c) Derive the best-case, average-case and worst-case time complexities of Quick Sort and explain under what input condition the worst case occurs.

(a) Quick Sort and the Partition Step

Quick Sort is a divide-and-conquer algorithm. It chooses a pivot, then partitions the array so that all elements smaller than the pivot lie to its left and all larger to its right; the pivot is then in its final sorted position. The two partitions are sorted recursively.

Partitioning (Lomuto scheme, pivot = last element):

partition(A, lo, hi):
    pivot = A[hi]; i = lo - 1
    for j = lo to hi-1:
        if A[j] <= pivot:
            i = i + 1; swap A[i], A[j]
    swap A[i+1], A[hi]
    return i+1   // final pivot index

Example on [7, 2, 9, 3], pivot = 3: elements ≤3 (2) moved left → [2, 3, 9, 7] with 3 in place; recurse on [2] and [9,7] → sorted [2,3,7,9].

(b) Merge Sort of [38, 27, 43, 3, 9, 82, 10]

Division:

[38, 27, 43, 3, 9, 82, 10]
  -> [38, 27, 43, 3]            [9, 82, 10]
  -> [38,27] [43,3]            [9,82] [10]
  -> [38][27] [43][3]          [9][82] [10]

Merging (combine sorted halves):

[38]+[27]   -> [27,38]
[43]+[3]    -> [3,43]
[27,38]+[3,43] -> [3,27,38,43]
[9]+[82]    -> [9,82]
[9,82]+[10] -> [9,10,82]
[3,27,38,43] + [9,10,82] -> [3,9,10,27,38,43,82]

Sorted array: [3, 9, 10, 27, 38, 43, 82].

(c) Time Complexity of Quick Sort

Let T(n)T(n) be the running time on nn elements; partitioning costs Θ(n)\Theta(n).

  • Best case — pivot splits the array into two equal halves:
T(n)=2T(n/2)+Θ(n)=O(nlogn)T(n) = 2T(n/2) + \Theta(n) = O(n \log n)
  • Average case — random/typical input, reasonably balanced splits: O(nlogn)O(n \log n).
  • Worst case — pivot is always the smallest or largest element, giving splits of size n1n-1 and 00:
T(n)=T(n1)+Θ(n)=O(n2)T(n) = T(n-1) + \Theta(n) = O(n^2)

Worst-case input condition: the array is already sorted (ascending or descending) when the first or last element is chosen as pivot, producing maximally unbalanced partitions. Using a randomized or median-of-three pivot makes the worst case very unlikely. Space: O(logn)O(\log n) average recursion stack (O(n)O(n) worst case).

sorting-algorithmsalgorithm-complexity
B

Section B: Short Answer Questions

Attempt all / any as specified.

7 questions
5short7 marks

Write a recursive function to compute the n-th Fibonacci number. Draw the recursion tree for fib(5), and explain why this recursive approach has exponential time complexity. Suggest one technique to improve its efficiency.

Recursive Fibonacci

int fib(int n) {
    if (n <= 1)
        return n;          // fib(0)=0, fib(1)=1
    return fib(n-1) + fib(n-2);
}

Recursion Tree for fib(5)

              fib(5)
            /        \
        fib(4)        fib(3)
        /    \        /    \
   fib(3)  fib(2)  fib(2)  fib(1)
   /  \    /  \    /  \
fib(2) f(1) f(1) f(0) f(1) f(0)
 /  \
f(1) f(0)

Many subproblems (e.g. fib(3), fib(2)) are recomputed multiple times.

Why Exponential

Each call spawns two more calls, so the number of calls roughly doubles with n. The recurrence is T(n)=T(n1)+T(n2)+O(1)T(n) = T(n-1) + T(n-2) + O(1), whose solution grows like Θ(ϕn)\Theta(\phi^n) where ϕ1.618\phi \approx 1.618 — i.e. exponential, O(2n)O(2^n). The same values are computed over and over (overlapping subproblems).

Improvement

Use memoization (top-down DP) — store each computed fib(i) in an array/cache and reuse it — or bottom-up dynamic programming iterating from fib(0) upward. This reduces the time to O(n)O(n) (and space to O(1)O(1) for the iterative two-variable version).

recursiontime-complexity
6short7 marks

Write an algorithm to reverse a singly linked list in place (without using extra nodes), and explain its time and space complexity. List two advantages of a doubly linked list over a singly linked list.

Reverse a Singly Linked List In Place

Use three pointers and reverse each next link while traversing once.

Node* reverse(Node* head) {
    Node *prev = NULL, *curr = head, *next = NULL;
    while (curr != NULL) {
        next = curr->next;   // save next node
        curr->next = prev;   // reverse the link
        prev = curr;         // advance prev
        curr = next;         // advance curr
    }
    return prev;             // new head
}

Complexity

  • Time: O(n)O(n) — each node is visited exactly once.
  • Space: O(1)O(1) — only a constant number of pointers are used; no extra nodes are allocated (in-place).

Two Advantages of Doubly over Singly Linked List

  1. Bidirectional traversal: a doubly linked list can be traversed both forward and backward using its prev and next pointers.
  2. Easier deletion / insertion before a node: given a pointer to a node, it can be deleted in O(1)O(1) (the previous node is directly accessible via prev), whereas a singly linked list needs the predecessor to be found first.
linked-lists
7short7 marks

What is a hash collision? Insert the keys 12, 22, 32, 42, 52 into a hash table of size 10 using the hash function h(k) = k mod 10, resolving collisions using (a) linear probing and (b) separate chaining. Show the resulting table in each case.

Hash Collision

A hash collision occurs when two distinct keys map to the same index of the hash table under the hash function, i.e. h(k1) == h(k2) for k1 ≠ k2. A collision-resolution method is then required to store both keys.

Here h(k) = k mod 10, so all keys 12, 22, 32, 42, 52 hash to index 2 — every insertion after the first collides.

(a) Linear Probing

On collision, probe the next slot: (h(k) + i) mod 10, i = 0,1,2,...

  • 12 → 2 (empty) → index 2
  • 22 → 2 occupied → 3 → index 3
  • 32 → 2,3 occupied → 4 → index 4
  • 42 → 2,3,4 occupied → 5 → index 5
  • 52 → 2,3,4,5 occupied → 6 → index 6
Index0123456789
Key1222324252

(b) Separate Chaining

Each slot holds a linked list of all keys hashing to it. All five keys hash to index 2:

IndexChain
0
1
212 → 22 → 32 → 42 → 52
3–9

In chaining, no probing is needed; collisions are simply appended to the list at that index.

hashingsearching
8short7 marks

Define Big-O, Big-Omega and Big-Theta notations. Arrange the following functions in increasing order of growth rate: n!, n log n, 2^n, n^2, log n, n. Justify the placement of n log n relative to n^2.

Asymptotic Notations

Let f(n)f(n) and g(n)g(n) be non-negative functions.

  • Big-O (OO) — upper bound: f(n)=O(g(n))f(n) = O(g(n)) if there exist constants c>0,n0c>0, n_0 such that f(n)cg(n)f(n) \le c\,g(n) for all nn0n \ge n_0. Describes the worst-case growth.
  • Big-Omega (Ω\Omega) — lower bound: f(n)=Ω(g(n))f(n) = \Omega(g(n)) if f(n)cg(n)f(n) \ge c\,g(n) for all nn0n \ge n_0. Describes the best-case / minimum growth.
  • Big-Theta (Θ\Theta) — tight bound: f(n)=Θ(g(n))f(n) = \Theta(g(n)) if it is both O(g(n))O(g(n)) and Ω(g(n))\Omega(g(n)), i.e. c1g(n)f(n)c2g(n)c_1 g(n) \le f(n) \le c_2 g(n). The function grows exactly at that rate.

Increasing Order of Growth

logn  <  n  <  nlogn  <  n2  <  2n  <  n!\log n \;<\; n \;<\; n \log n \;<\; n^2 \;<\; 2^n \;<\; n!

Justification: nlognn \log n vs n2n^2

Divide both by nn: we compare logn\log n with nn. Since logn\log n grows much more slowly than nn (for large nn, lognn\log n \ll n), it follows that nlognn2n \log n \ll n^2. Hence nlognn \log n is placed before n2n^2 in the ordering.

algorithm-complexityasymptotic-notation
9short7 marks

Write the algorithm for binary search on a sorted array and trace it to search for the key 23 in the array [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]. Explain why binary search cannot be applied directly to a singly linked list.

Binary Search Algorithm (sorted array)

int binarySearch(int A[], int n, int key) {
    int low = 0, high = n - 1;
    while (low <= high) {
        int mid = low + (high - low) / 2;
        if (A[mid] == key)  return mid;      // found
        else if (A[mid] < key) low = mid + 1; // search right half
        else high = mid - 1;                  // search left half
    }
    return -1;  // not found
}

Trace: search 23 in [2, 5, 8, 12, 16, 23, 38, 56, 72, 91] (indices 0–9)

SteplowhighmidA[mid]Action
10941616 < 23 → low = 5
25975656 > 23 → high = 6
356523found at index 5

Key 23 is found at index 5 in 3 comparisons. Time complexity: O(logn)O(\log n).

Why Not on a Singly Linked List

Binary search needs constant-time random access to the middle element. A singly linked list provides only sequential access — reaching the middle node requires traversing from the head in O(n)O(n) time, and the list cannot be indexed directly. This destroys the O(logn)O(\log n) advantage, so binary search cannot be applied efficiently to a singly linked list.

searchingalgorithm-complexity
10short7 marks

What is an AVL tree? Insert the keys 30, 20, 10 into an empty AVL tree and show the rotation required to keep it balanced, naming the type of rotation performed. State the balance factor condition that every node of an AVL tree must satisfy.

AVL Tree

An AVL tree is a self-balancing Binary Search Tree in which, for every node, the heights of the left and right subtrees differ by at most 1. This keeps the tree height O(logn)O(\log n), guaranteeing O(logn)O(\log n) search, insert and delete.

Balance Factor Condition

For every node: BF=height(left subtree)height(right subtree)\text{BF} = height(\text{left subtree}) - height(\text{right subtree}), and it must satisfy

BF{1,0,+1}.\text{BF} \in \{-1, 0, +1\}.

If any node's balance factor becomes +2+2 or 2-2 after an insertion, a rotation restores balance.

Inserting 30, 20, 10

  1. Insert 30 → root.
  2. Insert 20 (<30) → left child. Tree still balanced (BF of 30 = +1).
   30
   /
  20
  1. Insert 10 (<30,<20) → left child of 20.
     30   (BF = +2  -> unbalanced)
     /
    20
    /
   10

Node 30 now has balance factor +2+2 with the imbalance in the left-left subtree.

Rotation required: Single Right Rotation (LL rotation) about node 30.

After rotation (balanced):

    20
   /  \
  10   30

Every node now has balance factor in {1,0,+1}\{-1,0,+1\}, so the AVL property is restored.

treesavl-treebalancing
11short6 marks

Differentiate between a stack and a queue with respect to insertion and deletion, and give one real-world application of each. Also explain how two stacks can be used to implement a queue.

Stack vs Queue

AspectStackQueue
PolicyLIFO (Last In, First Out)FIFO (First In, First Out)
InsertionAt one end — push at topAt the rear — enqueue
DeletionFrom the same end — pop at topFrom the front — dequeue

Real-world applications:

  • Stack: function call/return management (call stack), undo operation in editors, expression evaluation.
  • Queue: CPU/printer job scheduling, handling requests on a server (first-come first-served).

Implementing a Queue using Two Stacks

Use two stacks inStack and outStack.

  • Enqueue(x): push x onto inStack.
  • Dequeue(): if outStack is empty, pop every element from inStack and push it onto outStack (this reverses the order). Then pop and return the top of outStack.

Because the elements are reversed once when transferred, the element that entered first ends up on top of outStack, giving FIFO behaviour. Each element is pushed and popped at most twice, so the amortized cost per operation is O(1)O(1).

sorting-algorithmsstacks-queues

Frequently asked questions

Where can I find the BE Computer Engineering (Pokhara University) Data Structure and Algorithms (PU, CMP 160) question paper 2078?
The full BE Computer Engineering (Pokhara University) Data Structure and Algorithms (PU, CMP 160) 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 Algorithms (PU, CMP 160) 2078 paper come with solutions?
Yes. Every question on this Data Structure and Algorithms (PU, CMP 160) 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 (Pokhara University) Data Structure and Algorithms (PU, CMP 160) 2078 paper?
The BE Computer Engineering (Pokhara University) Data Structure and Algorithms (PU, CMP 160) 2078 paper carries 100 full marks and is meant to be completed in 180 minutes, across 11 questions.
Is practising this Data Structure and Algorithms (PU, CMP 160) past paper free?
Yes — reading and attempting this Data Structure and Algorithms (PU, CMP 160) past paper on Kekkei is completely free.