DSA Assignments 3rd Sem
DSA Assignments 3rd Sem
Introduction to DSA
A Data Structure and Algorithm (DSA) assignment is an essential component of computer science education,
as it lays the foundation for building efficient software applications. The assignment typically involves understanding
different ways to store, manipulate, and retrieve data effectively and applying logical steps to solve complex
computational problems.
Key Components of DSA:
1. Data Structures: Data structures are specialized formats for organizing, processing, and managing data.
Common types include:
• Arrays: A collection of elements stored in contiguous memory locations, ideal for fast indexing but
limited in resizing.
• Linked Lists: A sequence of nodes where each node contains data and a reference to the next node,
allowing dynamic memory usage and easy insertion and deletion.
• Stacks and Queues: Linear data structures that follow specific order principles, such as Last In, First
Out (LIFO) for stacks and First In, First Out (FIFO) for queues.
• Trees and Graphs: Hierarchical and networked structures, respectively, used to represent complex
relationships between data items, such as parent-child relationships in a tree or connections in a
graph.
• Hash Tables: Structures that use key-value pairs to allow efficient data retrieval by mapping keys to
specific values.
2. Algorithms: Algorithms are sequences of instructions designed to perform tasks in a finite number of steps.
They are analyzed for their:
• Time Complexity: Measures the time an algorithm takes to complete as a function of input size. It’s
essential for optimizing speed, particularly for large datasets.
• Space Complexity: Measures the memory required by the algorithm, important for ensuring that the
solution is feasible in environments with limited resources.
Types of Algorithms Often Covered:
• Searching Algorithms: Techniques like binary search and linear search that allow finding elements within data
structures.
• Sorting Algorithms: Methods like quicksort, mergesort, and bubble sort that arrange data in a specific order,
useful for efficient data retrieval and organization.
• Traversal Algorithms: Used for accessing each element in a data structure, such as depth-first search (DFS)
and breadth-first search (BFS) for trees and graphs.
• Dynamic Programming: A technique for solving complex problems by breaking them down into simpler
overlapping subproblems, optimizing through memoization or tabulation.
• Greedy Algorithms: Solutions that make locally optimal choices at each step, aiming for a global optimum,
such as in minimum spanning tree algorithms.
Objectives of a DSA Assignment:
In a typical DSA assignment, students are expected to:
• Implement Data Structures: Code custom implementations of data structures like linked lists, stacks, and
trees to understand how they operate internally.
• Apply Algorithms: Use appropriate algorithms to solve specific problems, such as finding the shortest path in
a graph or sorting an array.
• Optimize Solutions: Analyze the complexity of their code and improve its efficiency by selecting the best data
structure and algorithm combination for the task.
• Debug and Test Code: Use debugging skills to identify and correct errors in code and run test cases to ensure
correctness and efficiency.
[1]
DSA Assignment
Assignment – 1: -
Write a program to search an element from a list. Give user the option to perform Linear or Binary
search.
❖ Objective:
The objective of this program is to allow users to search for a specific element within a list by
providing them with two options: Linear Search and Binary Search. Linear Search is a straightforward method
that checks each element in sequence, suitable for unsorted lists. Binary Search, on the other hand, is a more
efficient search method but requires the list to be sorted in ascending order. By allowing users to choose the
search method, the program demonstrates different algorithmic approaches to solving the same problem
and shows the trade-offs between simplicity and efficiency.
❖ Algorithm:
1. Linear Search:
1. Start with the first element of the list.
2. Initialize index to 0 (starting position in the list).
3. Repeat the following steps until index reaches the end of the list:
3.1. Compare arr[index] with target.
3.2. If arr[index] == target:
3.2.1. Return index (the position of the target in the list).
3.3. Increment index by 1 to move to the next element.
4. If the end of the list is reached and the target has not been found:
4.1. Return -1 to indicate that the target is not in the list.
2. Binary search:
1. Start by setting two pointers:
1.1. left = 0 (pointing to the beginning of the list)
1.2. right = n - 1 (pointing to the end of the list)
2. Repeat the following steps while left is less than or equal to right:
2.1. Calculate the middle index: mid = (left + right) / 2
2.2. Compare arr[mid] with target:
2.2.1. If arr[mid] == target, return mid (indicating the target was found at index mid).
2.2.2. If arr[mid] < target, update left = mid + 1 to search in the right half of the list.
2.2.3. If arr[mid] > target, update right = mid - 1 to search in the left half of the list.
3. If the loop completes without finding the target, return -1 (indicating the target is not in the list)
❖ Code:
1. Linear Search:
#include <stdio.h>
int main(void) {
int arr[] = {5, 3, 8, 6, 2, 9, 1}; // Sample array
int n = sizeof(arr) / sizeof(arr[0]); // Calculate size of the array
int target;
[2]
DSA Assignment
// Print result
if (find == -1) {
printf("Element not found in array\n");
} else {
printf("Element found at index: %d\n", find);
}
return 0;
}
2. Binary search:
#include <stdio.h>
int main(void) {
int arr[] = {1, 2, 3, 5, 6, 8, 9}; // Sorted array for binary search
int n = sizeof(arr) / sizeof(arr[0]); // Calculate size of the array
int target;
// Print result
if (result == -1) {
printf("Element not found in array\n");
} else {
printf("Element found at index: %d\n", result);
[3]
DSA Assignment
}
return 0;
}
❖ Conclusion:
Conclusion for Linear Search Code
The linear search code demonstrates a simple yet effective way to locate an element in an unsorted array.
By looping through each element and checking if it matches the target, this algorithm systematically searches
from the start to the end of the array. Each comparison is independent, making linear search easy to
implement and understand. However, due to its O(n) time complexity, linear search becomes inefficient as
the array size grows, because it may need to examine every element. This approach is well-suited for small
arrays or cases where sorting is not feasible, as no order is required among elements.
In the code, the main function initializes a sample array and calls linear_search, which returns the index of
the target if found, or -1 otherwise. This result is then displayed to the user.
[4]
DSA Assignment
reduces the number of comparisons, making binary search much faster than linear search for large datasets.
The code uses a sorted array and the binary_search function, which takes the array, its size, and the target
as arguments. By maintaining left and right pointers to represent the current search boundaries, the function
narrows down the search range iteratively. If the target is found, it returns the index; otherwise, it returns -1
to indicate the target isn't in the array. This is especially useful for large arrays, where binary search quickly
identifies if an element exists.
In both examples, linear and binary search illustrate different strengths: linear search is flexible and works
with any array but is slower for large arrays, while binary search requires sorting but excels in efficiency for
large, ordered datasets.
[5]
DSA Assignment
Assignment – 2: -
Write a program to sort a list of elements. Give user the option to perform sorting using Insertion
sort, Bubble sort or Selection sort.
❖ Objective:
To implement a C program that allows the user to sort a list of elements by choosing one of the three
sorting algorithms: Insertion Sort, Bubble Sort, or Selection Sort. The program aims to demonstrate the
functionality of sorting algorithms and provides an interactive experience for algorithm selection and
execution.
1. To design a user-interactive C program that sorts a list of elements based on the user’s choice of
sorting algorithm, enhancing understanding of sorting techniques and their operations.
2. To implement Insertion Sort, Bubble Sort, and Selection Sort as options for sorting and to allow
the user to compare their functionality and performance.
3. To provide flexibility for users to input a list of elements and view the sorted results,
demonstrating practical applications of sorting algorithms.
4. To reinforce algorithmic problem-solving skills by showcasing step-by-step sorting mechanisms
and ensuring accurate sorting of the elements.
5. To allow users to analyze and observe the differences in logic, iterations, and operations between
the three sorting methods for educational purposes.
❖ Algorithm:
1. Insertion Sort:
1. Start with the second element (consider the first element as sorted).
2. Compare the current element with the elements in the sorted portion of the array.
3. Shift all elements in the sorted portion that are greater than the current element one position to the
right.
4. Insert the current element into its correct position in the sorted portion.
5. Move to the next element in the unsorted portion and repeat steps 2–4 until the entire array is
sorted.
2. Bubble Sort:
1. Start with the first element of the array.
2. Compare the current element with the next element:
2.1. If the current element is greater than the next, swap them.
3. Move to the next pair of adjacent elements and repeat step 2 for the entire array.
4. After each pass, the largest element in the unsorted portion "bubbles up" to its correct position.
5. Reduce the unsorted portion by one element (ignoring the sorted end) and repeat steps 1–4 until the
array is sorted.
3. Selection Sort:
1. Start with the first element in the array.
2. Find the smallest element in the unsorted portion of the array.
3. Swap the smallest element with the first element of the unsorted portion.
4. Move the boundary between the sorted and unsorted portions one element forward.
5. Repeat steps 2–4 until the entire array is sorted.
❖ Code:
1. Insertion Sort:
#include <stdio.h>
[6]
DSA Assignment
// Function declarations
void print_array(int*, int); // Function to print the array
void insertion_sort(int*, int); // Function to perform insertion sort
int main(void) {
// Initialize the array
int arr[] = {5, 2, 8, 1, 9};
int n = sizeof(arr) / sizeof(arr[0]); // Calculate the size of the array
// Shift elements of the array that are greater than the key
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j]; // Move the larger element one position ahead
j--; // Move to the previous element
}
[7]
DSA Assignment
}
}
Result:
❖ Conclusion:
The program successfully implements Insertion Sort to sort an array of elements in ascending order.
By providing functions for both sorting and printing the array, the program is modular and easy to
understand. The use of a step-by-step sorting mechanism demonstrates how elements are shifted and
inserted into their correct positions, highlighting the logic behind the Insertion Sort algorithm. This
program serves as an excellent example of basic sorting techniques and can be extended to include other
sorting methods like Bubble Sort or Selection Sort for further learning and comparison.
2. Bubble Sort:
#include <stdio.h>
int main(void) {
int arr[] = {5, 2, 8, 1, 9};
int n = sizeof(arr) / sizeof(arr[0]);
return 0;
}
[8]
DSA Assignment
}
}
// If no swapping occurred, the array is already sorted
if (!swapped)
break;
}
}
Result:
❖ Conclusion:
The program successfully implements the Bubble Sort algorithm to sort an array in ascending order.
Bubble Sort repeatedly compares adjacent elements in the array and swaps them if they are in the wrong
order, "bubbling" the largest unsorted element to its correct position in each pass. This process continues
until the entire array is sorted. While Bubble Sort is simple to understand and implement, it is not the
most efficient for large datasets due to its O(n²) time complexity. Nonetheless, this program
demonstrates the core mechanics of the Bubble Sort algorithm, making it a valuable educational tool for
understanding sorting concepts.
3. Selection Sort:
#include <stdio.h>
int main(void) {
int arr[] = {5, 2, 8, 1, 9};
int n = sizeof(arr) / sizeof(arr[0]);
return 0;
}
[9]
DSA Assignment
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// Swap the found minimum element with the first element of the unsorted portion
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
}
Result:
❖ Conclusion:
Selection Sort is a straightforward and easy-to-implement sorting algorithm. It works well for small
datasets due to its simplicity. However, its time complexity of O(n2) for both the best and worst cases
makes it inefficient for larger datasets compared to more advanced sorting algorithms like Merge Sort or
Quick Sort. Despite this, its in-place sorting nature (requiring O(1) additional space) can be an advantage
in scenarios where memory is constrained. Overall, Selection Sort is an excellent choice for learning the
fundamentals of sorting algorithms and understanding basic algorithm design concepts.
[10]
DSA Assignment
Assignment – 3: -
Implement Linked List. Include functions for insertion, deletion and search of a number, reverse
the list and concatenate two linked lists.
❖ Objective:
The objective of this assignment is to develop a clear understanding of linked lists, a fundamental data
structure in computer science. Through implementing linked lists, you will:
1. Understand Linked List Structure: Learn how to represent and manipulate data using nodes and
pointers.
2. Develop Core Operations: Implement essential linked list operations, including insertion, deletion,
and searching for elements.
3. Manipulate the List: Practice advanced manipulations such as reversing the linked list and merging
two linked lists.
4. Enhance Problem-Solving Skills: Apply these concepts to solve problems efficiently, improving
algorithmic thinking and coding practices.
This assignment will provide hands-on experience and help solidify your grasp of linked lists and their
applications in real-world scenarios.
❖ Algorithm:
1. Insertion (at end):
- Create a new node.
- If head is NULL:
- Set head to the new node.
- Else:
- Traverse the list to the last node.
- Set last node's next to the new node.
4. Reverse:
- Initialize prev to NULL and current to head.
- While current is not NULL:
- Store current->next in a temporary variable.
[11]
DSA Assignment
- Update current->next to prev.
- Move prev to current.
- Move current to the next node.
- Update head to prev.
5. Concatenate:
- If head1 is NULL:
- Set head1 to head2.
- Else:
- Traverse head1 to the last node.
- Set last node's next to head2.
❖ Code:
#include <stdio.h>
#include <stdlib.h>
// Node structure
typedef struct Node {
int data;
struct Node* next;
} Node;
[12]
DSA Assignment
current->next = newNode;
}
}
if (list->head->data == value) {
Node* temp = list->head;
list->head = list->head->next;
free(temp);
return;
}
if (current->next) {
Node* temp = current->next;
current->next = current->next->next;
free(temp);
}
}
[13]
DSA Assignment
Result:
❖ Conclusion:
In this assignment, we implemented a Singly Linked List and demonstrated the core operations that
are essential for manipulating such data structures. The following functions were implemented:
1. Insertion: We added new nodes at the end of the list, allowing dynamic growth of the linked list
as elements are added.
2. Deletion: We created a method to remove a node by its value, ensuring that the integrity of the
list is maintained after removal.
3. Search: We provided a function to search for a particular value in the list, which traverses the
list from the head to the end.
4. Reverse: A function to reverse the entire list, re-linking nodes in the opposite order.
5. Concatenation: We demonstrated how to concatenate two linked lists, merging them into a
single list.
These functions together form the foundation of working with linked lists, which are a fundamental
data structure in computer science. This assignment also highlighted the importance of pointer
manipulation and dynamic memory allocation inherent to linked lists, providing an understanding of their
flexibility compared to arrays.
Through this implementation, we gained practical knowledge of how to efficiently perform common
linked list operations and how to handle edge cases like empty lists and non-existent elements. The linked
list, while simple in concept, is a versatile and important tool in algorithm design, useful in a variety of
applications such as memory management, data modeling, and real-time systems.
[14]
DSA Assignment
Assignment – 4: -
Implement Doubly Linked List. Include functions for insertion, deletion and search of a number,
reverse the list.
❖ Objective:
The objective of this assignment is to implement a Doubly Linked List (DLL), a data structure where each node
contains three parts: the data, a pointer to the next node, and a pointer to the previous node. The assignment
aims to:
Understand the structure of a doubly linked list: Learn how each node points both to the next and previous
nodes, allowing traversal in both directions.
Implement core operations:
Insertion: Add elements at the beginning, middle, or end of the list.
Deletion: Remove nodes by value, handling edge cases like deletion at the head, tail, or middle.
Search: Find if a specific value exists in the list.
Reversal: Reverse the order of the list using efficient traversal and pointer manipulation.
Explore the advantages of a doubly linked list: Understand how DLL allows easier bidirectional traversal
compared to singly linked lists and how this structure can be applied in various real-world problems.
❖ Algorithm:
1. Insertion at the End:
- Create a new node with the given data.
- If the list is empty:
- Set the new node as the head.
- Otherwise:
- Traverse to the last node.
- Set the last node's next to the new node.
- Set the new node's prev to the last node.
2. Deletion by Value:
- Traverse the list to find the node with the given value.
- If the node is the head:
- Set the next node as the new head.
- If the node is the tail:
- Set the previous node as the new tail.
- Otherwise:
- Update the prev and next pointers to remove the node.
- If the node is not found:
- Return an error.
[15]
DSA Assignment
- Traverse the list, swapping each node's next and prev pointers.
- Set the last node as the new head.
❖ Code:
#include <stdio.h>
#include <stdlib.h>
[16]
DSA Assignment
*head = temp->next;
if (*head != NULL) {
(*head)->prev = NULL;
}
free(temp);
return;
}
[17]
DSA Assignment
current->prev = current->next;
current->next = temp;
current = current->prev;
}
// Insert nodes
insert(&head, 10);
insert(&head, 20);
insert(&head, 30);
insert(&head, 40);
// Delete a node
delete(&head, 20);
printf("List after deleting 20:\n");
display(head);
[18]
DSA Assignment
return 0;
}
Result:
❖ Conclusion:
In this assignment, we successfully implemented a Doubly Linked List (DLL), a flexible data structure
that allows traversal in both forward and backward directions. The operations of insertion, deletion,
searching, and reversal were implemented as key functionalities for managing a DLL.
The insertion operation adds new nodes at the end of the list, while deletion removes nodes by value,
ensuring proper adjustments of neighboring node pointers. The search function allows efficient checking
of node existence, and the reverse operation swaps the direction of traversal by modifying the next and
prev pointers of each node.
Through this implementation, we explored how a DLL is more efficient than a singly linked list, especially
in scenarios requiring traversal in both directions. This assignment highlights the importance of pointer
manipulation in managing dynamic data structures and provides a foundation for more complex data
structures and algorithms.
[19]
DSA Assignment
Assignment – 5: -
Implement Circular Linked List. Include functions for insertion, deletion and search of a number,
reverse the list.
❖ Objective:
The objective of this assignment is to implement a Circular Linked List (CLL) and understand its functionality
and operations. The Circular Linked List is a type of linked list where the last node points back to the first node,
creating a circular structure. This assignment will help in understanding the differences between linear and
circular linked lists, and also demonstrate the various operations that can be performed on a circular linked list,
including:
1. Insertion: Adding nodes at various positions in the circular linked list (e.g., insertion at the beginning,
middle, or end).
2. Deletion: Removing nodes by value or position from the circular list while maintaining the circular
property.
3. Search: Finding a node in the circular linked list by its value.
4. Reversal: Reversing the circular linked list, ensuring that the circular property is maintained after the
reversal.
❖ Algorithm:
1. Insertion at the End:
- Create a new node.
- If the list is empty:
- Make the new node the head.
- Point the new node's next to itself.
- Otherwise:
- Traverse to the last node.
- Set the last node's next to the new node.
- Point the new node's next to the head.
3. Deletion by Value:
- If the list is empty:
- Return.
- Find the node with the given value:
- If it's the head:
- Update the head to the next node.
- Update the last node's next to the new head.
- Otherwise:
[20]
DSA Assignment
- Update the previous node's next to skip the node.
- Free the node.
[21]
DSA Assignment
if (temp->data == value) {
prev->next = temp->next;
free(temp);
}
}
[22]
DSA Assignment
curr = next;
} while (curr != *head);
last->next = prev;
*head = prev;
}
int main() {
struct Node* head = NULL;
// Insert nodes
insert(&head, 10);
insert(&head, 20);
insert(&head, 30);
insert(&head, 40);
display(head);
// Delete a node
delete(&head, 20);
display(head);
return 0;
}
[23]
DSA Assignment
Result:
❖ Conclusion:
In this assignment, we successfully implemented a Circular Linked List (CLL), a variation of the
standard linked list where the last node points back to the head, forming a circular structure. This
structure allows for continuous traversal without the need for termination conditions.
We implemented key operations on the circular linked list:
• Insertion at the end and the beginning of the list.
• Deletion of nodes by value, ensuring that the circular nature of the list is maintained.
• Searching for a node by its value, enabling efficient value lookup.
• Reversal of the list, ensuring the circular property was preserved after the reversal.
The circular linked list is particularly useful for applications where the list needs to be traversed
repeatedly or when data needs to be accessed in a circular manner, such as in round-robin
scheduling or implementing circular queues.
[24]
DSA Assignment
Assignment – 6: -
Perform Stack operations using Linked List implementation.
❖ Objective:
The objective of this assignment is to implement a Stack data structure using a Linked List and to understand
the advantages of dynamic memory allocation in managing stack operations. A stack is a linear data structure
that follows the Last In, First Out (LIFO) principle, where elements are added and removed only from the top of
the stack.
This assignment aims to:
1. Implement Stack Operations:
o Push: Add an element to the top of the stack.
o Pop: Remove the topmost element from the stack.
o Peek: Retrieve the topmost element without removing it.
o IsEmpty: Check if the stack is empty.
2. Explore Linked List-Based Implementation:
o Demonstrate the use of linked lists to dynamically manage stack size.
o Avoid the limitations of fixed size that occur in array-based stack implementations.
❖ Algorithm:
1. Push:
- Create a new node with data.
- If head is NULL: head = new node.
- Else: newNode->next = head, head = newNode.
2. Pop:
- If head is NULL: print error, exit.
- Else: temp = head, head = head->next, free(temp).
3. Peek:
- If head is NULL: print error, exit.
- Else: return head->data.
4. IsEmpty:
- Return head == NULL.
❖ Code:
#include <stdio.h>
#include <stdlib.h>
[25]
DSA Assignment
newNode->data = data;
newNode->next = NULL;
return newNode;
}
[26]
DSA Assignment
pop(&stack);
printf("Top element is %d\n", peek(stack));
pop(&stack);
pop(&stack);
printf("Is stack empty? %s\n", isEmpty(stack) ? "Yes" : "No");
return 0;
}
Result:
❖ Conclusion:
In this assignment, we successfully implemented a Stack data structure using a Linked List, showcasing
the flexibility of dynamic memory allocation over static array-based stacks. The implementation included
core stack operations such as:
• Push: Adding elements to the top of the stack.
• Pop: Removing the topmost element.
• Peek: Viewing the top element without altering the stack.
• IsEmpty: Checking if the stack is empty.
The linked list-based implementation eliminates the size constraints of arrays, allowing the stack to grow
or shrink dynamically as needed. This approach is particularly useful in scenarios where the maximum
size of the stack cannot be predetermined.
[27]
DSA Assignment
Assignment – 7: -
Perform Stack operations using Array implementation.
❖ Objective:
The objective of this assignment is to implement a Stack data structure using an Array and to understand how
stack operations can be performed efficiently in a fixed-size, contiguous memory structure. A stack follows the
Last In, First Out (LIFO) principle, where elements are added and removed only from the top.
The key objectives include:
1. Implement Core Stack Operations:
o Push: Add an element to the top of the stack.
o Pop: Remove the topmost element from the stack.
o Peek: Retrieve the top element without removing it.
o IsEmpty: Check if the stack is empty.
o IsFull: Check if the stack is full.
2. Understand Array-Based Implementation:
o Use a fixed-size array to implement the stack, highlighting its memory efficiency.
o Explore the limitations of array-based stacks, such as size constraints.
3. Practical Application:
o Understand real-world use cases of stacks, such as function call management, expression evaluation,
and backtracking algorithms.
❖ Algorithm:
1. Push:
- If top == MAX_SIZE - 1: print "Overflow", exit.
- Else: top++, stack[top] = value.
2. Pop:
- If top == -1: print "Underflow", exit.
- Else: value = stack[top], top--.
3. Peek:
- If top == -1: print "Empty", exit.
- Else: return stack[top].
4. IsEmpty:
- Return top == -1.
5. IsFull:
- Return top == MAX_SIZE - 1.
❖ Code:
#include <stdio.h>
#define MAX_SIZE 100 // Maximum size of the stack
[28]
DSA Assignment
// Initialize the stack
void initialize(Stack* stack) {
stack->top = -1;
}
[29]
DSA Assignment
push(&stack, 10);
push(&stack, 20);
push(&stack, 30);
printf("Top element is %d\n", peek(&stack));
pop(&stack);
printf("Top element is %d\n", peek(&stack));
pop(&stack);
pop(&stack);
printf("Is stack empty? %s\n", isEmpty(&stack) ? "Yes" : "No");
return 0;
}
Result:
❖ Conclusion:
In this assignment, we successfully implemented a Stack data structure using an Array, demonstrating
the core stack operations:
• Push: Adding elements to the top of the stack.
• Pop: Removing the topmost element.
• Peek: Viewing the top element without modifying the stack.
• IsEmpty: Checking whether the stack is empty.
• IsFull: Checking whether the stack has reached its maximum capacity.
The array-based implementation highlights the simplicity and efficiency of using a fixed-size memory
structure for stack operations. However, it also underscores the limitation of a predefined maximum size,
which could lead to stack overflow if exceeded.
This assignment provided a clear understanding of the Last In, First Out (LIFO) principle and its practical
application in scenarios like expression evaluation, recursion handling, and backtracking. Additionally, it
reinforced fundamental concepts of array manipulation and error handling, which are essential in
computer programming.
[30]
DSA Assignment
Assignment – 8: -
❖ Objective:
The objective of this assignment is to implement a Queue data structure using both Array and Linked List
approaches, comparing their functionality and performance. A queue is a linear data structure that follows the
First In, First Out (FIFO) principle, where elements are added at one end (rear) and removed from the other end
(front).
The key objectives include:
1. Implement Core Queue Operations:
o Enqueue: Add an element to the rear of the queue.
o Dequeue: Remove an element from the front of the queue.
o Peek: Retrieve the front element without removing it.
o IsEmpty: Check if the queue is empty.
o IsFull (Array implementation): Check if the queue is full.
2. Explore Array and Linked List Implementations:
o Array-Based Queue: Understand fixed-size limitations and how circular queues can optimize
space.
o Linked List-Based Queue: Demonstrate dynamic memory allocation, overcoming the constraints
of a fixed-size array.
3. Analyze Use Cases:
o Study real-world applications of queues, such as task scheduling, buffering in data streams, and
breadth-first search in graphs.
❖ Algorithm:
Array-Based Queue:
1. Enqueue:
- If rear == MAX_SIZE - 1: print "Overflow", exit.
- Else: rear++, queue[rear] = value.
2. Dequeue:
- If front > rear: print "Underflow", exit.
- Else: value = queue[front], front++.
3. Peek:
- If front > rear: print "Empty", exit.
- Else: return queue[front].
4. IsEmpty:
- Return front > rear.
5. IsFull:
- Return rear == MAX_SIZE - 1.
[31]
DSA Assignment
2. Dequeue:
- If front == NULL: print "Underflow", exit.
- Else: value = front->data, front = front->next.
- If front == NULL: rear = NULL.
- Free removed node.
3. Peek:
- If front == NULL: print "Empty", exit.
- Else: return front->data.
4. IsEmpty:
- Return front == NULL.
❖ Code:
Array-Based Queue Implementation:
#include <stdio.h>
#define MAX_SIZE 5 // Define maximum size of the queue
[32]
DSA Assignment
if (isFull(q)) {
printf("Queue Overflow! Cannot enqueue %d.\n", value);
return;
}
q->data[++q->rear] = value;
printf("%d enqueued to the queue.\n", value);
}
enqueue(&q, 10);
enqueue(&q, 20);
enqueue(&q, 30);
printf("Front element is %d\n", peek(&q));
dequeue(&q);
printf("Front element is %d\n", peek(&q));
dequeue(&q);
dequeue(&q);
printf("Is queue empty? %s\n", isEmpty(&q) ? "Yes" : "No");
return 0;
}
[33]
DSA Assignment
Result:
if (isEmpty(q)) {
[34]
DSA Assignment
q->front = q->rear = newNode;
} else {
q->rear->next = newNode;
q->rear = newNode;
}
printf("%d enqueued to the queue.\n", value);
}
if (q->front == NULL) {
q->rear = NULL;
}
enqueue(&q, 10);
enqueue(&q, 20);
enqueue(&q, 30);
printf("Front element is %d\n", peek(&q));
dequeue(&q);
printf("Front element is %d\n", peek(&q));
dequeue(&q);
dequeue(&q);
[35]
DSA Assignment
printf("Is queue empty? %s\n", isEmpty(&q) ? "Yes" : "No");
return 0;
}
Result:
❖ Conclusion:
This code demonstrates two different implementations of a Queue data structure, one using an Array
and the other using a Linked List. Both implementations effectively showcase the First In, First Out (FIFO)
principle and cover the basic queue operations like Enqueue, Dequeue, and Peek. While the array-based
implementation has a fixed size, the linked list implementation provides dynamic memory allocation,
making it more flexible. Both implementations are efficient for real-world applications such as scheduling
and buffering.
[36]
DSA Assignment
Assignment – 9: -
Create and perform different operations on Double-ended Queues using Linked List
implementation.
❖ Objective:
The objective of this assignment is to implement and perform various operations on a Double-Ended
Queue (Deque) using a Linked List. A deque is a versatile data structure that allows insertion and
deletion of elements from both the front and the rear, making it highly flexible for numerous
applications.
The key objectives include:
1. Understanding the Deque Data Structure:
o Comprehend the functionality of a deque and its differences from traditional queues.
o Learn about the two types of deques: Input-Restricted (insertion at one end) and Output-
Restricted (deletion at one end).
2. Implement Core Operations:
o Insert at the Front: Add an element to the front of the deque.
o Insert at the Rear: Add an element to the rear of the deque.
o Delete from the Front: Remove an element from the front.
o Delete from the Rear: Remove an element from the rear.
o Peek: Retrieve the front or rear element without removal.
o Check if Empty: Verify if the deque is empty.
3. Linked List Implementation:
o Use a linked list to dynamically manage memory, eliminating the constraints of fixed-size
structures like arrays.
4. Explore Applications:
o Study real-world scenarios such as job scheduling, caching, and sliding window algorithms,
where deques are highly beneficial.
❖ Algorithm:
1. Insert at Front:
- Create newNode with value.
- If front == NULL: front = rear = newNode.
- Else: newNode->next = front, front->prev = newNode, front = newNode.
2. Insert at Rear:
- Create newNode with value.
- If rear == NULL: front = rear = newNode.
- Else: newNode->prev = rear, rear->next = newNode, rear = newNode.
[37]
DSA Assignment
- Else: value = rear->data, rear = rear->prev.
- If rear != NULL: rear->next = NULL.
- Else: front = NULL.
- Free the removed node.
5. Peek at Front:
- If front == NULL: print "Empty", exit.
- Else: return front->data.
6. Peek at Rear:
- If rear == NULL: print "Empty", exit.
- Else: return rear->data.
7. Check if Empty:
- Return front == NULL.
❖ Code:
#include <stdio.h>
#include <stdlib.h>
[38]
DSA Assignment
if (isEmpty(dq)) {
dq->rear = newNode;
} else {
dq->front->prev = newNode;
}
dq->front = newNode;
printf("%d inserted at the front.\n", value);
}
if (isEmpty(dq)) {
dq->front = newNode;
} else {
dq->rear->next = newNode;
}
dq->rear = newNode;
printf("%d inserted at the rear.\n", value);
}
dq->front = dq->front->next;
if (dq->front == NULL) {
dq->rear = NULL;
} else {
dq->front->prev = NULL;
}
free(temp);
}
[39]
DSA Assignment
struct Node* temp = dq->rear;
printf("%d deleted from the rear.\n", temp->data);
dq->rear = dq->rear->prev;
if (dq->rear == NULL) {
dq->front = NULL;
} else {
dq->rear->next = NULL;
}
free(temp);
}
insertFront(&dq, 10);
insertRear(&dq, 20);
insertFront(&dq, 5);
peekFront(&dq);
peekRear(&dq);
deleteFront(&dq);
deleteRear(&dq);
peekFront(&dq);
peekRear(&dq);
deleteFront(&dq);
deleteFront(&dq);
[40]
DSA Assignment
return 0;
}
Result:
❖ Conclusion:
The implementation of a Double-Ended Queue (Deque) using a Linked List demonstrates the versatility
of the deque data structure in allowing efficient insertion and deletion operations at both ends. By
utilizing a doubly linked list, we overcome the limitations of fixed-size arrays, enabling dynamic memory
management and flexibility.
The key takeaways from this assignment are:
1. Efficient Operations:
o Both insertion and deletion at the front and rear are performed in constant time O(1),
making the deque ideal for scenarios requiring frequent updates at both ends.
2. Dynamic Memory Usage:
o The linked list-based implementation eliminates the need for predefined capacity, ensuring
efficient use of memory without wastage.
3. Practical Applications:
o Deques are widely used in real-world applications such as caching, job scheduling,
and implementing sliding window algorithms.
This assignment reinforces the understanding of advanced data structures and their practical
significance in solving computational problems efficiently.
[41]
DSA Assignment
Assignment – 10: -
Write a program to scan a polynomial using linked list and add two polynomials.
❖ Objective:
The objective of this assignment is to implement a program that performs polynomial addition using a linked
list. A polynomial is represented as a sequence of terms, each consisting of a coefficient and an exponent. Using
a linked list provides a dynamic and efficient way to handle polynomials of varying sizes.
Key objectives include:
1. Understanding Polynomial Representation:
o Represent a polynomial as a linked list where each node contains a term's coefficient and exponent.
2. Scanning and Constructing Polynomials:
o Accept a polynomial from the user in terms of its coefficients and exponents.
o Dynamically construct a linked list to store the polynomial.
3. Polynomial Addition:
o Traverse two polynomials represented as linked lists.
o Perform addition by combining terms with the same exponent.
o Create a new linked list to store the result.
4. Dynamic Memory Management:
o Use linked lists to handle polynomials of arbitrary size without predefined constraints.
5. Practical Applications:
o Explore how polynomial manipulation can be applied in mathematical computations, scientific
modeling, and computer algebra systems.
❖ Algorithm:
1. Represent Polynomial:
- Define Node(coefficient, exponent, next).
2. Input/Scan Polynomial:
- Initialize an empty linked list.
- For each term:
- Input coefficient, exponent.
- Create newNode(coefficient, exponent).
- Insert newNode in descending order of exponent.
[42]
DSA Assignment
4. Display Polynomial:
- Traverse result list.
- Print each term as: coefficient*x^exponent or coefficient (if exponent == 0).
❖ Code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int coefficient, exponent;
struct Node* next;
};
[43]
DSA Assignment
}
return result;
}
int main() {
struct Node* poly1 = NULL, *poly2 = NULL;
int n, coef, exp;
return 0;
}
[44]
DSA Assignment
Result:
❖ Conclusion:
The implementation of Polynomial Addition using Linked Lists highlights the efficiency of dynamic
data structures in representing and manipulating mathematical expressions. By using a linked list, the
program can handle polynomials of arbitrary sizes and degrees without predefined constraints.
Key takeaways include:
1. Dynamic Representation:
o Polynomials are stored dynamically, optimizing memory usage.
2. Efficient Operations:
o Addition is performed by traversing and combining terms with the same exponents.
3. Scalability:
o The program adapts seamlessly to varying numbers of terms or polynomial sizes.
[45]
DSA Assignment
Assignment – 11: -
Write a program to create a Binary Search Tree and include following operations in tree:
(a) Insertion (Recursive and Iterative Implementation).
(b) Deletion.
(c) Search a node in BST.
(d) Display its preorder, postorder and inorder traversals recursively.
(e) Display its preorder, postorder and inorder traversals Iteratively.
(f) Display its level-by-level traversals.
(g) Count the non-leaf nodes and leaf nodes.
(h) Display height of tree.
(i) Create a mirror image of tree.
❖ Objective:
The objective of this assignment is to implement a Binary Search Tree (BST) and perform various operations
on the tree, both recursively and iteratively. The main goal is to understand the construction, manipulation, and
traversal of trees, specifically a Binary Search Tree, and gain familiarity with fundamental tree operations.
Key objectives include:
1. Binary Search Tree Construction:
o Understand and implement the core principles of a Binary Search Tree, where each node follows the
property: left child < parent < right child.
2. Insertion Operations:
o Implement recursive and iterative methods for inserting nodes into the tree while maintaining the
BST property.
3. Deletion of Nodes:
o Handle node deletion, considering the three cases: deleting a leaf node, deleting a node with one
child, and deleting a node with two children.
4. Searching for a Node:
o Implement search functionality to locate a node in the BST, utilizing the BST property for efficient
searching.
5. Traversal Operations:
o Display tree nodes using preorder, postorder, and inorder traversal techniques, both recursively and
iteratively.
6. Level-By-Level Traversal:
o Implement level-order traversal, commonly known as breadth-first traversal (BFS), to visit all nodes
level by level.
7. Counting Leaf and Non-Leaf Nodes:
o Count the number of leaf nodes (nodes with no children) and non-leaf nodes (nodes with at least one
child).
8. Height of the Tree:
o Calculate and display the height of the tree, which is the longest path from the root to a leaf node.
9. Creating a Mirror Image of the Tree:
o Implement functionality to create a mirror image of the binary search tree by swapping the left and
right children recursively.
[46]
DSA Assignment
❖ Algorithm:
1. Create a Binary Search Tree (BST):
- Node Structure: data, left, right.
- Root: First inserted node becomes root.
3. Deletion:
- Leaf Node: Remove the node.
- One Child: Replace with its only child.
- Two Children: Find inorder successor/predecessor, replace node with it, delete successor/predecessor.
4. Search a Node:
- Start at root, compare target with current node.
- Move left if smaller, right if greater.
- Repeat until node is found or subtree is empty.
5. Traversals (Recursive):
- Preorder (Root, Left, Right):
- Visit root, traverse left, traverse right.
- Postorder (Left, Right, Root):
- Traverse left, traverse right, visit root.
- Inorder (Left, Root, Right):
- Traverse left, visit root, traverse right.
6. Traversals (Iterative):
- Preorder Iterative:
- Use a stack, push root, pop node, visit, push right and left children.
- Postorder Iterative:
- Use two stacks, push root to first stack, pop to second, visit in postorder.
- Inorder Iterative:
- Use a stack, traverse left, pop and visit, move to right child.
[47]
DSA Assignment
- If node is NULL, return -1.
- Recursively calculate left and right subtree heights.
- Height of node = 1 + max(left height, right height).
// Recursive Insertion
struct Node* insertRecursive(struct Node* root, int data) {
if (root == NULL) {
return createNode(data);
}
if (data < root->data) {
root->left = insertRecursive(root->left, data);
} else {
root->right = insertRecursive(root->right, data);
}
return root;
}
// Iterative Insertion
struct Node* insertIterative(struct Node* root, int data) {
struct Node* newNode = createNode(data);
if (root == NULL) {
return newNode;
}
[48]
DSA Assignment
struct Node* current = root;
struct Node* parent = NULL;
while (current != NULL) {
parent = current;
if (data < current->data) {
current = current->left;
} else {
current = current->right;
}
}
if (data < parent->data) {
parent->left = newNode;
} else {
parent->right = newNode;
}
return root;
}
// Deletion of a node
struct Node* deleteNode(struct Node* root, int data) {
if (root == NULL) return root;
if (data < root->data) {
root->left = deleteNode(root->left, data);
} else if (data > root->data) {
root->right = deleteNode(root->right, data);
} else {
// Node to be deleted found
[49]
DSA Assignment
if (root->left == NULL) {
struct Node* temp = root->right;
free(root);
return temp;
} else if (root->right == NULL) {
struct Node* temp = root->left;
free(root);
return temp;
} else {
struct Node* temp = findMin(root->right);
root->data = temp->data;
root->right = deleteNode(root->right, temp->data);
}
}
return root;
}
[50]
DSA Assignment
printf("%d ", current->data);
if (current->right) stack[++top] = current->right;
if (current->left) stack[++top] = current->left;
}
}
// Push left and right children of the popped node onto stack1
if (current->left) stack1[++top1] = current->left;
if (current->right) stack1[++top1] = current->right;
}
[51]
DSA Assignment
}
// Main function
int main() {
[52]
DSA Assignment
struct Node* root = NULL;
root = insertRecursive(root, 50);
root = insertRecursive(root, 30);
root = insertRecursive(root, 70);
root = insertRecursive(root, 20);
root = insertRecursive(root, 40);
root = insertRecursive(root, 60);
root = insertRecursive(root, 80);
root = mirror(root);
printf("Inorder Traversal of Mirror Tree: ");
inorderRecursive(root);
printf("\n");
return 0;
}
[53]
DSA Assignment
Result:
❖ Conclusion:
In this assignment, we implemented a Binary Search Tree (BST) and performed various operations such
as insertion, deletion, search, and traversal. The tree was manipulated using both recursive and iterative
methods. The operations implemented include:
• Insertion (Recursive and Iterative): We used both methods to insert new nodes in the tree while
maintaining the BST property.
• Deletion: A node in the tree was deleted by considering different cases such as no children, one
child, and two children.
• Search: We implemented the search operation to find a node in the tree efficiently.
• Traversal: We implemented several tree traversal techniques including preorder, inorder, and
postorder traversals both recursively and iteratively. Additionally, level-order traversal (breadth-first
search) was implemented.
• Count of Leaf and Non-Leaf Nodes: We calculated the number of leaf and non-leaf nodes in the
tree.
• Height Calculation: The height of the tree was calculated using a recursive approach.
• Mirror Image: We created a mirror image of the tree, swapping the left and right subtrees.
This assignment provided a comprehensive understanding of how Binary Search Trees work and how
various operations can be efficiently performed on them. The iterative and recursive approaches were
explored to give a broader understanding of algorithm design and tree manipulations.
[54]
DSA Assignment
Assignment – 12: -
Write a program to reverse the order of the elements in the stack using additional stack.
❖ Objective:
The objective of this assignment is to implement a program that reverses the order of elements in a stack
using an additional stack. The program should perform the following tasks:
1. Stack Operations: Implement basic stack operations such as push and pop.
2. Reversal of Stack: Reverse the order of the elements in the stack using an additional stack as temporary
storage.
3. Demonstrate the Use of Two Stacks: The assignment will help in understanding how two stacks can be
used for data manipulation and how stack operations are fundamental to many algorithms.
4. Understanding Stack Behavior: By reversing the elements in the stack, the assignment will allow the
student to understand the Last-In-First-Out (LIFO) nature of stacks and how it affects data processing.
❖ Algorithm:
1. Initialize Two Stacks:
- Create stack1 (original stack) and stack2 (temporary stack).
5. Result:
- stack1 is now reversed compared to the original order.
[55]
DSA Assignment
stack->capacity = capacity;
stack->top = -1;
stack->array = (int*)malloc(stack->capacity * sizeof(int));
return stack;
}
[56]
DSA Assignment
free(stack2->array);
free(stack2);
}
// Main function
int main() {
int n, element;
reverseStack(stack);
free(stack->array);
free(stack);
return 0;
}
[57]
DSA Assignment
Result:
❖ Conclusion:
This assignment effectively demonstrates the use of stacks and their operations to solve a practical
problem—reversing the order of elements. By leveraging an additional stack, the program reinforces the
understanding of the Last-In-First-Out (LIFO) nature of stacks and highlights the importance of auxiliary
data structures in problem-solving.
The implementation showcases:
• The practical application of basic stack operations like push and pop.
• Efficient use of dynamic memory allocation for stack creation and management.
• A systematic approach to reversing elements, ensuring clarity and correctness.
Through this assignment, the concept of stack manipulation and its utility in real-world scenarios is
solidified.
[58]
DSA Assignment
Assignment – 13: -
Write a program to reverse the order of the elements in the stack using additional Queue.
❖ Objective:
The objective of this assignment is to implement a program that reverses the order of elements in a stack
using an additional queue. The program aims to:
1. Understand Stack and Queue Operations:
o Learn the fundamental operations of both data structures, such as push, pop, enqueue, and
dequeue.
2. Reversal of Stack Using Queue:
o Use the First-In-First-Out (FIFO) property of the queue to reverse the Last-In-First-Out (LIFO)
property of the stack.
3. Demonstrate the Use of Multiple Data Structures:
o Highlight how stacks and queues can work together to achieve data manipulation tasks.
4. Enhance Problem-Solving Skills:
o Reinforce the importance of algorithmic thinking by solving a problem that combines two
different data structures.
❖ Algorithm:
1. Initialize Two Stacks:
- Create stack1 (original stack) and stack2 (temporary stack).
5. Result:
- stack1 is now reversed compared to the original order.
[59]
DSA Assignment
// Define structure for queue
struct Queue {
int data[100];
int front, rear;
};
// Initialize stack
void initStack(struct Stack* stack) {
stack->top = -1;
}
// Initialize queue
void initQueue(struct Queue* queue) {
queue->front = 0;
queue->rear = -1;
}
[60]
DSA Assignment
struct Queue queue;
initQueue(&queue);
// Main function
int main() {
struct Stack stack;
initStack(&stack);
int n, value;
printf("Enter the number of elements in the stack: ");
scanf("%d", &n);
reverseStackUsingQueue(&stack);
return 0;
}
[61]
DSA Assignment
Result:
❖ Conclusion:
This assignment demonstrates the effective use of a queue to reverse the order of elements in a stack.
By leveraging the First-In-First-Out (FIFO) property of the queue, we successfully reversed the Last-In-
First-Out (LIFO) property of the stack.
Through this implementation, the following concepts were reinforced:
1. Understanding of Data Structures:
o The unique properties and operations of stacks and queues.
2. Interoperability of Data Structures:
o Using one data structure (queue) to manipulate and enhance another (stack).
3. Problem-Solving Skills:
o Applying logical thinking to solve real-world problems involving data organization and
manipulation.
This assignment provides a practical understanding of stack and queue operations, their applications, and
how they can work together to achieve specific outcomes.
[62]
DSA Assignment
ACKNOWLEDGEMENT
I would like to extend my heartfelt gratitude to Dr. Sumana Bandyopadhyay, whose
expert guidance and continuous support have been pivotal in the successful
completion of DSA assignment. Dr. Bandyopadhyay's profound knowledge and
insightful feedback not only helped me navigate the intricacies of DSA but also
inspired me to approach the subject with greater curiosity and dedication. Her
patience in answering my questions, providing clarity on challenging concepts, and
encouraging me to think critically has been invaluable in shaping my understanding of
the subject.
Furthermore, I would like to sincerely thank my classmates and friends, who have
been a constant source of encouragement and collaboration throughout this project.
Their willingness to exchange ideas, provide constructive criticism, and offer moral
support created an enriching learning environment. Together, we worked through
coding challenges, debugged errors, and explored various programming techniques,
which significantly contributed to my learning and the quality of this assignment.
In conclusion, this assignment would not have been possible without the collective
support and encouragement of those around me. To each and every one of you,
thank you for your contributions to my academic journey and for making this
endeavor a rewarding experience.
Thank you,
-----------------------------------------------
[Signature of Head of the Department]
[63]