Browse papers
A

Section A: Long Answer Questions

Attempt all / any as specified.

4 questions
1long14 marks

(a) Define asymptotic notations. Explain Big-O, Big-Omega (Ω\Omega) and Big-Theta (Θ\Theta) notations with the help of suitable graphs and examples. (8)

(b) Compute the worst-case and best-case running time of the following code segment in terms of Big-O notation, clearly showing the frequency count of each statement: (6)

for (i = 0; i < n; i++) {
    for (j = i; j < n; j++) {
        sum = sum + a[i][j];
    }
}

(a) Asymptotic Notations

Asymptotic notations describe the limiting behaviour of an algorithm's running time as the input size nn grows large. They let us compare algorithms independent of machine and constants.

Big-O (Upper Bound)

f(n)=O(g(n))f(n) = O(g(n)) if there exist constants c>0c > 0 and n0>0n_0 > 0 such that

0f(n)cg(n)for all nn0.0 \le f(n) \le c\,g(n) \quad \text{for all } n \ge n_0.

It gives the worst-case (upper) bound. Example: 3n2+2n+1=O(n2)3n^2 + 2n + 1 = O(n^2).

Graph: cg(n)c\,g(n) lies above f(n)f(n) for all nn0n \ge n_0.

Big-Omega (Ω\Omega) (Lower Bound)

f(n)=Ω(g(n))f(n) = \Omega(g(n)) if there exist c>0c > 0 and n0>0n_0 > 0 such that

0cg(n)f(n)for all nn0.0 \le c\,g(n) \le f(n) \quad \text{for all } n \ge n_0.

It gives the best-case (lower) bound. Example: 3n2+2n=Ω(n2)3n^2 + 2n = \Omega(n^2).

Graph: cg(n)c\,g(n) lies below f(n)f(n) for all nn0n \ge n_0.

Big-Theta (Θ\Theta) (Tight Bound)

f(n)=Θ(g(n))f(n) = \Theta(g(n)) if there exist c1,c2>0c_1, c_2 > 0 and n0n_0 such that

0c1g(n)f(n)c2g(n)for all nn0.0 \le c_1 g(n) \le f(n) \le c_2 g(n) \quad \text{for all } n \ge n_0.

It squeezes f(n)f(n) between two multiples of g(n)g(n) (both upper and lower bound). Example: 3n2+2n+1=Θ(n2)3n^2 + 2n + 1 = \Theta(n^2).

Graph: f(n)f(n) is sandwiched between c1g(n)c_1 g(n) and c2g(n)c_2 g(n) for all nn0n \ge n_0.

(b) Frequency Count of the Code

for (i = 0; i < n; i++) {        // outer loop
    for (j = i; j < n; j++) {    // inner loop
        sum = sum + a[i][j];     // body
    }
}

The inner loop runs (ni)(n - i) times for each value of ii. Total executions of the body:

i=0n1(ni)=n+(n1)++1=n(n+1)2.\sum_{i=0}^{n-1}(n-i) = n + (n-1) + \dots + 1 = \frac{n(n+1)}{2}.

Frequency count of the body statement =n(n+1)2=n2+n2= \dfrac{n(n+1)}{2} = \dfrac{n^2+n}{2}.

Since there is no early exit (no conditional break), the number of iterations is the same for every input. Therefore:

  • Best case: O(n2)O(n^2)
  • Worst case: O(n2)O(n^2)

The code is always Θ(n2)\Theta(n^2).

algorithm-complexitysorting-algorithms
2long14 marks

(a) What is an AVL tree? Construct an AVL tree by inserting the following keys one by one in the given order, showing the rotation performed (LL, RR, LR or RL) at each step where rebalancing is required: 30, 31, 32, 23, 22, 24, 16, 17, 18. (10)

(b) Differentiate between a binary tree and a binary search tree. Write down the in-order, pre-order and post-order traversal sequences of the final AVL tree obtained in part (a). (4)

(a) AVL Tree

An AVL tree is a self-balancing binary search tree in which, for every node, the balance factor (height of left subtree - height of right subtree) is 1-1, 00, or +1+1. When an insertion violates this, a rotation (LL, RR, LR, RL) restores balance.

Insertion of 30, 31, 32, 23, 22, 24, 16, 17, 18

  1. Insert 30 → root 30.
  2. Insert 31 → right child of 30. Balanced.
  3. Insert 32 → unbalanced at 30 (BF 2-2, right-right). RR rotation31 becomes root with children 30, 32.
  4. Insert 23 → goes left of 30. Balanced.
  5. Insert 22 → unbalanced at 30 (left-left). LL rotation at 30 → 23 with children 22,30. Tree: root 31, left 23 (children 22, 30), right 32.
  6. Insert 24 → right child of 23... it goes left of 30. Balanced (no violation).
  7. Insert 16 → left of 22. Unbalanced at 31 (BF +2+2, left subtree heavy, left-left). LL rotation at 31 → 23 becomes new root. Left child 22 (with child 16), right child 31 (with left 30 containing 24, right 32).
  8. Insert 17 → unbalanced at 22 (left-right: 16 then right 17). LR rotation → 17 becomes parent of 16 and 22.
  9. Insert 18 → unbalanced at 23 root region (left-right path 17→18). RL/LR rotation restores balance; 18 settles under 17.

Final balanced AVL tree

          23
        /     \
      17        31
     /  \      /   \
   16    22  30      32
          \   /
          18 24

(Heights satisfy |BF| ≤ 1 at every node.)

(b) Binary Tree vs Binary Search Tree

Binary TreeBinary Search Tree (BST)
Each node has at most 2 children; no ordering rule.Left subtree keys < node < right subtree keys.
No restriction on values.Strict ordering of keys.
Searching is O(n)O(n).Searching is O(logn)O(\log n) (balanced).
In-order traversal gives no special order.In-order traversal gives sorted order.

Traversals of the final tree

  • In-order (L, Root, R): 16, 17, 18, 22, 23, 24, 30, 31, 32 (sorted)
  • Pre-order (Root, L, R): 23, 17, 16, 22, 18, 31, 30, 24, 32
  • Post-order (L, R, Root): 16, 18, 22, 17, 24, 30, 32, 31, 23
treesbinary-search-trees
3long12 marks

(a) Consider a weighted, undirected graph with vertices {A, B, C, D, E} and the following edges with weights: A-B(4), A-C(1), C-B(2), B-D(5), C-D(8), C-E(10), D-E(2). Represent this graph using an adjacency matrix. (4)

(b) Apply Dijkstra's shortest path algorithm to find the shortest path from source vertex A to all other vertices. Show the contents of the distance table at every iteration. (8)

(a) Adjacency Matrix

Vertices {A, B, C, D, E}, undirected edges: A-B(4), A-C(1), C-B(2), B-D(5), C-D(8), C-E(10), D-E(2). Entry = weight, \infty (or 0) if no edge; matrix is symmetric.

ABCDE
A041\infty\infty
B4025\infty
C120810
D\infty5802
E\infty\infty1020

(b) Dijkstra's Algorithm from source A

Initialize dist[A]=0dist[A]=0, others ==\infty. At each iteration pick the unvisited vertex with minimum distance and relax its neighbours.

IterationVisitedABCDE
Init0
1: pick A (0){A}041
2: pick C (1){A,C}03 (1+2)19 (1+8)11 (1+10)
3: pick B (3){A,C,B}0318 (3+5)11
4: pick D (8){A,C,B,D}031810 (8+2)
5: pick E (10)all031810

Final shortest distances and paths from A

  • A → A: 0
  • A → C: 1 (A→C)
  • A → B: 3 (A→C→B)
  • A → D: 8 (A→C→B→D)
  • A → E: 10 (A→C→B→D→E)
graphsgraph-traversal
4long10 marks

(a) Convert the following infix expression into its equivalent postfix expression using a stack, showing the status of the stack and output at each scanned symbol: A + B * (C - D) / E ^ F. (6)

(b) Explain how recursion is implemented internally using the system stack. Write a recursive function to compute the factorial of a non-negative integer and trace its execution for n = 4. (4)

(a) Infix → Postfix: A + B * (C - D) / E ^ F

Precedence: ^ (highest, right-assoc) > *,/ > +,-. Scan left to right; operands go to output, operators are pushed respecting precedence.

SymbolStackOutput
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
^+ / ^A B C D - * E
F+ / ^A B C D - * E F
end(pop all)A B C D - * E F ^ / +

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

(b) Recursion and the System Stack

When a function calls itself, the system pushes an activation record (stack frame) onto the call stack containing the return address, parameters, and local variables. Each recursive call adds a new frame; when a call returns, its frame is popped and control returns to the caller. The base case stops the recursion and unwinding begins.

int factorial(int n) {
    if (n == 0)            // base case
        return 1;
    return n * factorial(n - 1);   // recursive case
}

Trace for n = 4

factorial(4) = 4 * factorial(3)
factorial(3) = 3 * factorial(2)
factorial(2) = 2 * factorial(1)
factorial(1) = 1 * factorial(0)
factorial(0) = 1            <- base case, stack unwinds
=> factorial(1) = 1*1 = 1
=> factorial(2) = 2*1 = 2
=> factorial(3) = 3*2 = 6
=> factorial(4) = 4*6 = 24

Result: 4! = 24.

stacks-and-queuesrecursion
B

Section B: Short Answer Questions

Attempt all / any as specified.

8 questions
5short7 marks

Write an algorithm (or C function) to insert a node at the beginning, at the end, and after a given node in a singly linked list. State one advantage of a linked list over an array.

Insertion in a Singly Linked List

struct Node { int data; struct Node *next; };

// 1. Insert at the BEGINNING
struct Node* insertBegin(struct Node *head, int x) {
    struct Node *n = malloc(sizeof(struct Node));
    n->data = x;
    n->next = head;   // point to old head
    return n;         // new head
}

// 2. Insert at the END
struct Node* insertEnd(struct Node *head, int x) {
    struct Node *n = malloc(sizeof(struct Node));
    n->data = x; n->next = NULL;
    if (head == NULL) return n;
    struct Node *t = head;
    while (t->next != NULL) t = t->next;  // go to last node
    t->next = n;
    return head;
}

// 3. Insert AFTER a given node p
void insertAfter(struct Node *p, int x) {
    if (p == NULL) return;
    struct Node *n = malloc(sizeof(struct Node));
    n->data = x;
    n->next = p->next;   // link new node to p's successor
    p->next = n;         // link p to new node
}

Advantage of a linked list over an array: A linked list is dynamic — it can grow or shrink at run time without a fixed size, and insertion/deletion at the front (or after a known node) takes O(1)O(1) time without shifting elements, whereas an array requires shifting and has fixed capacity.

linked-lists
6short7 marks

Insert the keys 72, 27, 36, 24, 63, 81, 92 into a hash table of size 10 using the hash function h(k)=kmod10h(k) = k \bmod 10. Resolve collisions using quadratic probing. Show the final contents of the hash table.

Hashing with Quadratic Probing

Table size m=10m = 10, h(k)=kmod10h(k) = k \bmod 10. On collision, probe positions (h(k)+i2)mod10(h(k) + i^2) \bmod 10 for i=1,2,3,i = 1, 2, 3, \dots

Insert 72, 27, 36, 24, 63, 81, 92:

  • 7272%10=272\%10 = 2. Slot 2 empty → place at 2.
  • 27 → 7. Empty → 7.
  • 36 → 6. Empty → 6.
  • 24 → 4. Empty → 4.
  • 63 → 3. Empty → 3.
  • 81 → 1. Empty → 1.
  • 92 → 2 (occupied by 72). Probe i=1i=1: (2+1)%10=3(2+1)\%10 = 3 (occupied by 63). Probe i=2i=2: (2+4)%10=6(2+4)\%10 = 6 (occupied by 36). Probe i=3i=3: (2+9)%10=11%10=1(2+9)\%10 = 11\%10 = 1 (occupied by 81). Probe i=4i=4: (2+16)%10=18%10=8(2+16)\%10 = 18\%10 = 8 (empty) → place at 8.

Final Hash Table

Index0123456789
Key81726324362792
searching-and-hashing
7short6 marks

Sort the following list using quick sort, taking the first element as the pivot. Show the array after each partitioning step: 44, 33, 11, 55, 77, 90, 40, 60, 99, 22, 88. State the worst-case time complexity of quick sort and the input condition that causes it.

Quick Sort (first element as pivot)

List: 44, 33, 11, 55, 77, 90, 40, 60, 99, 22, 88

Pass 1 — pivot = 44. Partition so elements < 44 go left, > 44 go right. 44 settles into its sorted position: [33, 11, 40, 22] 44 [77, 90, 55, 60, 99, 88]

Left sublist [33, 11, 40, 22], pivot = 33: [11, 22] 33 [40] → gives [11, 22, 33, 40]

  • sub [11, 22], pivot 11 → 11 [22][11, 22].

Right sublist [77, 90, 55, 60, 99, 88], pivot = 77: [55, 60] 77 [90, 99, 88]

  • [55, 60], pivot 55 → 55 [60][55, 60].
  • [90, 99, 88], pivot 90 → [88] 90 [99][88, 90, 99].

Combine: 11, 22, 33, 40, 44, 55, 60, 77, 88, 90, 99

Sorted array

11, 22, 33, 40, 44, 55, 60, 77, 88, 90, 99

Worst-case complexity

The worst case of quick sort is O(n2)O(n^2). It occurs when the pivot is always the smallest or largest element, producing maximally unbalanced partitions (one side empty). With first-element pivot this happens when the input is already sorted (ascending or descending).

sorting-algorithms
8short6 marks

What is a circular queue? Explain how it overcomes the limitation of a linear queue. Write the conditions to detect queue-full and queue-empty states in a circular queue implemented using an array.

Circular Queue

A circular queue is a linear data structure in which the last position is logically connected back to the first position, forming a circle. The array indices wrap around using modulo arithmetic: after the last index, the next index becomes 0.

How it overcomes the linear-queue limitation

In a simple linear queue implemented with an array, after several enqueue/dequeue operations the front and rear pointers keep moving forward. Even when the front portion of the array is empty, the rear may reach the end and the queue is wrongly reported as full — this wastes space (false overflow). A circular queue reuses the vacated front slots by wrapping rear (and front) around with (index+1)modsize(\text{index} + 1) \bmod size, so all array cells can be used.

Full and Empty conditions (array of size SIZE)

Using front and rear initialized to 1-1:

  • Queue Empty: front == -1
  • Queue Full: (rear + 1) % SIZE == front

Enqueue: rear = (rear + 1) % SIZE. Dequeue: if front == rear set both to 1-1, else front = (front + 1) % SIZE.

stacks-and-queues
9short6 marks

Explain radix sort with a suitable example. Sort the list 170, 45, 75, 90, 802, 24, 2, 66 using radix sort and show the buckets/passes. Compare its complexity with comparison-based sorting algorithms.

Radix Sort

Radix sort is a non-comparison, integer sorting algorithm that sorts numbers digit by digit, from the least significant digit (LSD) to the most significant digit. In each pass it distributes elements into 10 buckets (0–9) based on the current digit using a stable sort (counting sort), then collects them back.

Sorting: 170, 45, 75, 90, 802, 24, 2, 66

Pass 1 — units digit:

Bucket0123456789
Keys170, 90802, 22445, 7566

Collect → 170, 90, 802, 2, 24, 45, 75, 66

Pass 2 — tens digit:

Bucket0123456789
Keys802, 2244566170, 7590

Collect → 802, 2, 24, 45, 66, 170, 75, 90

Pass 3 — hundreds digit:

Bucket012...8
Keys2, 24, 45, 66, 75, 90170802

Collect → 2, 24, 45, 66, 75, 90, 170, 802

Sorted output

2, 24, 45, 66, 75, 90, 170, 802

Complexity comparison

Radix sort runs in O(d(n+b))O(d \cdot (n + b)) where dd = number of digits and bb = base (10). For fixed-width integers this is effectively O(n)O(n) linear time, beating the O(nlogn)O(n \log n) lower bound of comparison-based sorts (merge sort, quick sort, heap sort). The trade-off is extra space O(n+b)O(n + b) and that it works only for integers/fixed-length keys.

sorting-algorithms
10short6 marks

Differentiate between Breadth First Search (BFS) and Depth First Search (DFS) traversal of a graph. For the graph having edges {(1,2),(1,3),(2,4),(3,4),(4,5),(3,5)}, write the BFS and DFS traversal order starting from vertex 1.

BFS vs DFS

Breadth First Search (BFS)Depth First Search (DFS)
Explores level by level (all neighbours first).Explores as deep as possible along a branch before backtracking.
Uses a queue (FIFO).Uses a stack / recursion (LIFO).
Finds shortest path (fewest edges) in unweighted graphs.Does not guarantee shortest path.
Higher memory (stores whole frontier).Lower memory along a single path.
Time: O(V+E)O(V + E).Time: O(V+E)O(V + E).

Traversal from vertex 1

Edges: (1,2),(1,3),(2,4),(3,4),(4,5),(3,5). Adjacency (ascending order):

  • 1 → 2, 3
  • 2 → 1, 4
  • 3 → 1, 4, 5
  • 4 → 2, 3, 5
  • 5 → 3, 4

BFS (queue, visit neighbours in ascending order): Start 1 → visit 2, 3 → from 2 visit 4 → from 3 visit 5. BFS order: 1, 2, 3, 4, 5

DFS (stack/recursion, ascending order): 1 → 2 → 4 → 3 → 5. (1, go to 2; from 2 go to 4; from 4 go to 3; from 3 go to 5.) DFS order: 1, 2, 4, 3, 5

graphsgraph-traversal
11short6 marks

Construct a binary search tree (BST) by inserting the keys 50, 30, 70, 20, 40, 60, 80, 10 in the given order. Then show the resulting tree after deleting the node with key 30, explaining the deletion case applied.

Building and Deleting in a BST

Insert 50, 30, 70, 20, 40, 60, 80, 10

Applying the BST rule (smaller left, larger right):

          50
        /    \
      30      70
     /  \    /  \
   20    40 60   80
   /
  10

Delete node with key 30

Node 30 has two children (20 and 40). This is the deletion case for a node with two children: replace the node with its in-order successor (smallest key in the right subtree) — here the successor is 40 — then remove that successor node.

Replace 30 with 40; node 40 (a leaf) is deleted from its old place. Resulting tree:

          50
        /    \
      40      70
     /       /  \
   20      60    80
   /
  10

(Alternatively, the in-order predecessor 20 could be used; both are valid. In-order traversal of the result — 10, 20, 40, 50, 60, 70, 80 — remains sorted, confirming correctness.)

treesbinary-search-trees
12short6 marks

Write a recursive algorithm for the Tower of Hanoi problem with n disks. Derive its recurrence relation and solve it to show that the number of moves required is 2n12^n - 1.

Tower of Hanoi

Move nn disks from source peg A to destination peg C using auxiliary peg B, never placing a larger disk on a smaller one.

Recursive algorithm

void hanoi(int n, char A, char C, char B) {
    if (n == 1) {                       // base case
        printf("Move disk 1 from %c to %c\n", A, C);
        return;
    }
    hanoi(n - 1, A, B, C);              // 1. move top n-1 from A to B
    printf("Move disk %d from %c to %c\n", n, A, C); // 2. move largest to C
    hanoi(n - 1, B, C, A);              // 3. move n-1 from B to C
}

Recurrence relation

Let T(n)T(n) be the number of moves for nn disks. Moving n1n-1 disks twice plus one move for the largest disk:

T(n)=2T(n1)+1,T(1)=1.T(n) = 2\,T(n-1) + 1, \qquad T(1) = 1.

Solving by back-substitution

T(n)=2T(n1)+1T(n) = 2T(n-1) + 1 =2[2T(n2)+1]+1=22T(n2)+2+1= 2[2T(n-2)+1] + 1 = 2^2 T(n-2) + 2 + 1 =23T(n3)+22+2+1= 2^3 T(n-3) + 2^2 + 2 + 1 \vdots =2n1T(1)+(2n2++2+1)= 2^{n-1} T(1) + (2^{n-2} + \dots + 2 + 1) =2n1+(2n11)=2n1.= 2^{n-1} + (2^{n-1} - 1) = 2^n - 1.

(Using T(1)=1T(1)=1 and the geometric sum k=0n12k=2n1\sum_{k=0}^{n-1} 2^k = 2^n - 1.)

Result

T(n)=2n1\boxed{T(n) = 2^n - 1}

So nn disks require 2n12^n - 1 moves, giving time complexity O(2n)O(2^n).

recursionalgorithm-complexity

Frequently asked questions

Where can I find the BE Computer Engineering (Pokhara University) Data Structure and Algorithms (PU, CMP 160) question paper 2079?
The full BE Computer Engineering (Pokhara University) Data Structure and Algorithms (PU, CMP 160) 2079 (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) 2079 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) 2079 paper?
The BE Computer Engineering (Pokhara University) Data Structure and Algorithms (PU, CMP 160) 2079 paper carries 100 full marks and is meant to be completed in 180 minutes, across 12 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.