CSCDSC152: Lab on Data Structure
This document provides a comprehensive guide to all programming assignments listed in the CSCDSC152 syllabus. It includes the core logic, algorithms, and implementation tips needed for a practical exam or viva.
Table of Contents
Course Objectives & Outcomes
Course Objectives
The main objectives of this lab are to:
- Apply the theoretical concepts of data structures in a practical programming environment.
- Implement and manipulate various data structures like arrays, lists, stacks, queues, and trees.
- Enhance programming, debugging, and testing skills related to data structures.
- Gain practical knowledge of how data structures are used to solve problems.
Course Outcomes
Upon successful completion, students will be able to:
- Demonstrate a solid understanding of data structures like arrays, linked lists, stacks, queues, trees, and hash tables.
- Implement these data structures and their associated algorithms in a programming language.
- Analyze the time and space complexity of these algorithms.
A Note on C++ Templates
Many assignments specify using templates. This allows you to write generic code that works with any data type (e.g., int, float, char).
A template class for a Stack would start like this:
template <typename T> class Stack { private: T arr[100]; int top; public: void push(T data) { // ... logic } T pop() { // ... logic } // ... other methods }; When you create an object, you specify the type:
Stack<int> intStack; (A stack for integers)
Stack<float> floatStack; (A stack for floats)
The same logic applies to template functions for sorting or searching.
Section 1: Searching, Sorting & Matrix Assignments
Assignment 1: Linear & Binary Search (Templates)
Task: Write a template program to search an element from a list, offering users the option of Linear or Binary search.
Logic
- Template Function: Your search functions should be template functions.
template <typename T> int linearSearch(T arr[], int size, T key) - Linear Search:
- Iterate from
i = 0tosize - 1. - If
arr[i] == key, returni(index found). - If loop finishes, return
-1(not found).
- Iterate from
- Binary Search:
- Prerequisite: The array must be sorted. You should sort it first (using a sort from Assignment 2).
- Set
low = 0,high = size - 1. - While
low <= high:mid = low + (high - low) / 2.- If
arr[mid] == key, returnmid. - If
arr[mid] < key, setlow = mid + 1. - If
arr[mid] > key, sethigh = mid - 1.
- If loop finishes, return
-1.
Assignment 2: Insertion, Bubble & Selection Sort (Templates)
Task: Write a template program (WAP) to sort a list, offering users options for Insertion, Bubble, or Selection sort.
Logic
- Bubble Sort:
- Outer loop from
i = 0ton-2. - Inner loop from
j = 0ton-i-2. - If
arr[j] > arr[j+1], swap them.
- Outer loop from
- Selection Sort:
- Outer loop from
i = 0ton-2. - Find the index of the minimum element (
min_idx) in the range[i, n-1]. - Swap
arr[i]witharr[min_idx].
- Outer loop from
- Insertion Sort:
- Outer loop from
i = 1ton-1. - Store
key = arr[i]. - Set
j = i - 1. - While
j >= 0andarr[j] > key:arr[j+1] = arr[j](shift element to the right).j = j - 1.
arr[j+1] = key(insert key in its correct position).
- Outer loop from
Assignment 15: Sparse Matrix Conversion
Task: WAP to convert a Sparse Matrix into non-zero form and vice-versa.
Logic
The "non-zero form" (or Triplet Form) stores only non-zero elements in a k x 3 matrix, where k is the number of non-zero elements.
triplet[k][3] -> [row, column, value]
A header row triplet[0] is often used to store [total_rows, total_cols, total_non_zero].
- Sparse to Triplet:
- Create a
tripletmatrix. Initializek = 1(for data, row 0 is header). - Iterate through the original
M x Nmatrix with nested loops (ifor row,jfor col). - If
matrix[i][j] != 0:triplet[k][0] = itriplet[k][1] = jtriplet[k][2] = matrix[i][j]k++
- Finally, set header:
triplet[0][0] = M,triplet[0][1] = N,triplet[0][2] = k - 1.
- Create a
- Triplet to Sparse:
- Read the header:
M = triplet[0][0],N = triplet[0][1],non_zero = triplet[0][2]. - Create a new
M x Nmatrix and initialize all its elements to 0. - Loop from
k = 1tonon_zero:row = triplet[k][0]col = triplet[k][1]val = triplet[k][2]- Set
matrix[row][col] = val.
- The
matrixis now reconstructed.
- Read the header:
Assignments 18, 19, 20, 21: Special Matrix Implementations
Task: Implement Diagonal, Lower Triangular, Upper Triangular, and Symmetric matrices using a 1D array.
Logic
The goal is to save space by only storing the non-zero (or unique) elements in a 1D array. This requires a "mapping formula" to convert 2D (i, j) indices to a 1D (k) index.
- Diagonal Matrix: Only
M[i][i]elements are non-zero.- Store only the
ndiagonal elements. Formula:arr[i]storesM[i][i].
- Store only the
- Lower Triangular: Elements
M[i][j]are non-zero only ifi >= j.- Number of elements =
n(n+1)/2. - Row-Major Formula:
k = i(i+1)/2 + j
- Number of elements =
- Upper Triangular: Elements
M[i][j]are non-zero only ifi <= j.- Number of elements =
n(n+1)/2. - Row-Major Formula:
k = i*n - i(i-1)/2 + j - i
- Number of elements =
- Symmetric Matrix:
M[i][j] == M[j][i].- Store only the lower or upper triangle. Use the same formula as that triangle.
Section 2: Recursion Assignments
Assignment 11: Factorial (Recursive vs. Iterative)
Logic
- Iterative:
function factorial_iter(n): result = 1 for i = 2 to n: result = result * i return result
- Recursive:
function factorial_recur(n): if n == 0 or n == 1: return 1 // Base Case else: return n * factorial_recur(n - 1) // Recursive Step
Assignment 12: Fibonacci (Recursive vs. Iterative)
Logic
- Iterative (Efficient):
function fib_iter(n): if n <= 1: return n a = 0, b = 1, c for i = 2 to n: c = a + b a = b b = c return b
- Recursive (Inefficient):
function fib_recur(n): if n <= 1: return n // Base Cases (0 and 1) else: return fib_recur(n - 1) + fib_recur(n - 2)
Assignment 13: GCD (Recursive vs. Iterative)
Logic (using Euclidean Algorithm)
- Iterative:
function gcd_iter(a, b): while b != 0: temp = b b = a % b a = temp return a
- Recursive:
function gcd_recur(a, b): if b == 0: return a // Base Case else: return gcd_recur(b, a % b) // Recursive Step
Section 3: Linked List Assignments
Node structure. template <typename T> struct Node { T data; Node* next; // For Singly & Circular Node* prev; // For Doubly }; Assignment 3: Singly Linked List (Templates)
Task: Implement insertion, deletion, search, reverse, and concatenate.
Logic
- Insertion: At beginning (O(1)), at end (O(n)), at specific position (O(n)).
- Deletion: At beginning (O(1)), at end (O(n)), at specific position (O(n)).
- Search: Traverse the list from
head, comparingdata. Returntrueor the node if found,false/NULLotherwise. - Reverse:
- Use three pointers:
prev = NULL,current = head,next = NULL. - Loop while
current != NULL:next = current->nextcurrent->next = prev(reverse the link)prev = currentcurrent = next
- Finally, set
head = prev.
- Use three pointers:
- Concatenate (list1 + list2):
- Traverse
list1to find its last node. - Set
last_node_of_list1->next = list2->head. - (Be careful not to destroy
list2; the+operator should ideally create a new list or appendlist2tolist1).
- Traverse
Assignment 4: Doubly Linked List (Templates)
Task: Implement insertion, deletion, search, and reverse.
Logic
Key: Every operation must correctly update both next and prev pointers.
- Insertion (e.g., after a node
p):newNode->next = p->nextnewNode->prev = p- If
p->next != NULL, thenp->next->prev = newNode p->next = newNode
- Deletion (of node
p):p->prev->next = p->next- If
p->next != NULL, thenp->next->prev = p->prev delete p
- Reverse:
- Traverse the list. For each node, swap its
prevandnextpointers. - Finally, swap the
headandtailpointers of the list.
- Traverse the list. For each node, swap its
Assignment 5: Circular Linked List (Templates)
Task: Implement insertion, deletion, search, and reverse.
Logic
Key: The list never has a NULL end. The head's "previous" is the tail, and the tail's next is the head. A tail pointer is often maintained instead of a head, as tail->next gives you the head.
- Traversal: Use a
do-whileloop to ensure the head is processed.temp = head; do { ...; temp = temp->next; } while (temp != head); - Insertion/Deletion: Similar to singly linked list, but with extra care when modifying the
headortail, as you must update thetail->nextpointer.
Assignment 10: Polynomial Addition
Task: WAP to scan a polynomial using a linked list and add two polynomials.
Logic
- Node Structure: Each node represents one term.
struct Term { int coeff; // Coefficient int exp; // Exponent Term* next; }; - Storage: Store the polynomial as a linked list, sorted in descending order of exponent.
- Addition (
poly1,poly2):- Create a new
resultlist. - Use two pointers,
p1(forpoly1) andp2(forpoly2). - While
p1 != NULLandp2 != NULL:- If
p1->exp > p2->exp: Addp1's term toresult, advancep1. - If
p1->exp < p2->exp: Addp2's term toresult, advancep2. - If
p1->exp == p2->exp: Add the coefficients (p1->coeff + p2->coeff). If the sum is not zero, add the new term toresult. Advance bothp1andp2.
- If
- When one list finishes, append the entire remainder of the other list to
result.
- Create a new
Section 4: Stack & Queue Assignments
Assignment 7: Stack using Array (Templates)
Logic
- Members:
T arr[MAX_SIZE],int top. - Constructor: Initialize
top = -1. - push(T data):
- Check for Overflow (
if top == MAX_SIZE - 1). top++.arr[top] = data.
- Check for Overflow (
- pop():
- Check for Underflow (
if top == -1). T data = arr[top].top--.- Return
data.
- Check for Underflow (
Assignment 6: Stack using Linked List
Logic
- Member:
Node* top(which is just theheadof the list). - Constructor: Initialize
top = NULL. - push(T data): (Insert at Beginning)
newNode = new Node(data).newNode->next = top.top = newNode.
- pop(): (Delete at Beginning)
- Check for Underflow (
if top == NULL). temp = top.T data = top->data.top = top->next.delete temp.- Return
data.
- Check for Underflow (
Assignment 8: Queue using Circular Array (Templates)
Logic
- Members:
T arr[MAX_SIZE],int front,int rear. - Constructor: Initialize
front = -1,rear = -1. - isFull():
return (rear + 1) % MAX_SIZE == front; - isEmpty():
return front == -1; - enqueue(T data):
- Check if full.
- If empty (
front == -1), setfront = 0. rear = (rear + 1) % MAX_SIZE.arr[rear] = data.
- dequeue():
- Check if empty.
T data = arr[front].- If
front == rear(only one element), setfront = -1,rear = -1. - Else,
front = (front + 1) % MAX_SIZE. - Return
data.
Assignment 9: Deque using Linked List
Task: Create and perform operations on a Double-ended Queue using a Doubly Linked List.
Logic
- Members:
Node* front,Node* rear(use a Doubly Linked List). - insertFront(): Insert at the beginning of the DLL.
- insertRear(): Insert at the end of the DLL.
- deleteFront(): Delete from the beginning of the DLL.
- deleteRear(): Delete from the end of the DLL.
front and rear pointers. When deleting the *last* element, you must set *both* front and rear to NULL. Assignment 16: Reverse Stack (using additional Stack)
Logic
This is simple. To reverse S1 using S2:
- While
S1is not empty,push(S1.pop())ontoS2. - Now
S2holds all elements in reverse order. - (Optional) If you need the reversed elements back in
S1, use a third stackS3(or a Queue) as an intermediary, or just assignS1 = S2if the class supports it.
Assignment 17: Reverse Stack (using additional Queue)
Logic
To reverse Stack S using Queue Q:
- While
Sis not empty,enqueue(S.pop())intoQ. (Elements are now inQin the original stack order). - While
Qis not empty,push(Q.dequeue())ontoS. (Elements are put back intoSin reverse order).
Section 5: Tree Assignments
Assignment 14: Binary Search Tree (BST) Operations
Task: Create a BST and implement a large number of operations.
Logic
- Node Structure:
{ T data; Node *left; Node *right; } - (a) Insertion (Recursive):
function insert(node, key): if node == NULL: return new Node(key) if key < node->data: node->left = insert(node->left, key) else: node->right = insert(node->right, key) return node
- (b) Deletion by Copying: (Case 3: 2 children)
- Find Inorder Successor (smallest node in the right subtree).
- Copy successor's data to the node to be deleted.
- Recursively delete the successor (which is an easier 0 or 1-child case).
- (c) Deletion by Merging: (Alternative Case 3)
- Find the largest node in the *left* subtree.
- Make the *entire right subtree* the right child of that largest node.
- Point the parent of the deleted node to the root of the left subtree.
- (d) Search: Similar to insertion, follow
left/rightpaths. Returntrueif found,falseifNULLis hit. - (e) Traversals (Recursive):
- Preorder:
visit(node),traverse(node->left),traverse(node->right). - Inorder:
traverse(node->left),visit(node),traverse(node->right). - Postorder:
traverse(node->left),traverse(node->right),visit(node).
- Preorder:
- (f) Traversals (Iterative): Use a Stack. (See theory notes for CSCDSC151, Unit 3).
- (g) Level-by-Level Traversal: Use a Queue.
- Enqueue the
root. - While Queue is not empty:
node = dequeue()visit(node)- If
node->left != NULL, enqueuenode->left. - If
node->right != NULL, enqueuenode->right.
- Enqueue the
- (h) Count Leaf & Non-Leaf Nodes:
function countLeaf(node): if node == NULL: return 0 if node->left == NULL and node->right == NULL: return 1 return countLeaf(node->left) + countLeaf(node->right) // Non-leaf is total_nodes - leaf_nodes
- (i) Display Height of Tree:
function height(node): if node == NULL: return -1 // or 0 for "count of nodes" return 1 + max(height(node->left), height(node->right))
- (j) Create Mirror Image:
function mirror(node): if node == NULL: return mirror(node->left) mirror(node->right) swap(node->left, node->right)
- (k) Check if Two BSTs are Equal:
function areEqual(r1, r2): if r1 == NULL and r2 == NULL: return true if r1 == NULL or r2 == NULL: return false return (r1->data == r2->data) and areEqual(r1->left, r2->left) and areEqual(r1->right, r2->right)
Assignment 22: Threaded Binary Tree
Task: Create a Threaded Binary Tree (TBT) as per inorder traversal and implement operations like find successor/predecessor, insert, and inorder traversal.
Logic
- Node Structure:
struct TBTNode { T data; TBTNode *left, *right; bool isLeftThread; // True if left pointer is a thread bool isRightThread; // True if right pointer is a thread }; - Inorder Traversal (without stack/recursion):
- Find the leftmost node of the tree.
- While
node != NULL:visit(node).- If
node->isRightThread == true,node = node->right(follow thread). - Else,
node = node->right, and then find the leftmost node of that subtree.
- Insertion: This is complex. You must find the correct empty spot, insert the new node, and update the
inorderandpredecessorthreads of the surrounding nodes.
Assignment 23: AVL Tree Operations
Task: Implement various operations on an AVL Tree.
Logic
This builds on Assignment 14 (BST). Your insert and delete functions must now be modified to include rebalancing.
- Perform the standard BST insertion/deletion.
- After the operation, move back up the tree (via recursion) to the root.
- At each node, update its height.
- Calculate the Balance Factor (BF):
BF = height(node->left) - height(node->right). - If
BF > 1(Left-Heavy):- If key was inserted in
node->left->left: Perform LL Rotate (Right Rotate). - If key was inserted in
node->left->right: Perform LR Rotate (Left-Right Rotate).
- If key was inserted in
- If
BF < -1(Right-Heavy):- If key was inserted in
node->right->right: Perform RR Rotate (Left Rotate). - If key was inserted in
node->right->left: Perform RL Rotate (Right-Left Rotate).
- If key was inserted in