0% found this document useful (0 votes)
21 views63 pages

DSA Assignments 3rd Sem

The DSA assignment focuses on teaching data structures and algorithms, emphasizing their importance in computer science education. It includes practical tasks such as implementing search algorithms (Linear and Binary Search) and sorting algorithms (Insertion, Bubble, and Selection Sort), allowing students to understand their functionalities and performance differences. The assignment aims to enhance algorithmic problem-solving skills through coding exercises and analysis of time and space complexities.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views63 pages

DSA Assignments 3rd Sem

The DSA assignment focuses on teaching data structures and algorithms, emphasizing their importance in computer science education. It includes practical tasks such as implementing search algorithms (Linear and Binary Search) and sorting algorithms (Insertion, Bubble, and Selection Sort), allowing students to understand their functionalities and performance differences. The assignment aims to enhance algorithmic problem-solving skills through coding exercises and analysis of time and space complexities.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 63

DSA Assignment

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 linear_search(int*, int, int);

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;

// Prompt user for the element to search


printf("Enter the element to search: ");
scanf("%d", &target);

[2]
DSA Assignment

// Perform linear search


int find = linear_search(arr, n, target);

// Print result
if (find == -1) {
printf("Element not found in array\n");
} else {
printf("Element found at index: %d\n", find);
}

return 0;
}

// Function to perform a linear search on an array


int linear_search(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // Return the index if the target is found
}
}
return -1; // Return -1 if the target is not found
}
Result:

2. Binary search:
#include <stdio.h>

int binary_search(int*, int, int);

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;

// Prompt user for the element to search


printf("Enter the element to search: ");
scanf("%d", &target);

// Perform binary search


int result = binary_search(arr, n, 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;
}

// Function to perform a binary search on a sorted array


int binary_search(int arr[], int size, int target) {
int left = 0, right = size - 1;

while (left <= right) {


int mid = left + (right - left) / 2;

// Check if target is present at mid


if (arr[mid] == target) {
return mid; // Return index if found
}

// If target is greater, ignore left half


if (arr[mid] < target) {
left = mid + 1;
}
// If target is smaller, ignore right half
else {
right = mid - 1;
}
}
return -1; // Return -1 if target is not found
}
Result:

❖ 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.

Conclusion for Binary Search Code


The binary search code showcases an efficient algorithm for finding an element in a sorted array by
dividing the search space in half with each iteration. Starting with the entire array, the algorithm checks the
middle element; if it matches the target, the search is complete. If not, it eliminates the half where the target
cannot be and continues searching the other half. This process, with its O(log n) complexity, significantly

[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

// Print the original array


printf("Original array: ");
print_array(arr, n);

// Perform insertion sort


insertion_sort(arr, n);

// Print the sorted array


printf("\nSorted array: ");
print_array(arr, n);

return 0; // Return 0 to indicate successful execution


}

// Function to print the elements of an array


void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) { // Loop through the array
printf("%d ", arr[i]); // Print each element
}
printf("\n"); // Print a newline
}

// Function to perform insertion sort


void insertion_sort(int arr[], int size) {
int key, j; // Variables for key and index

// Loop through each element starting from the second element


for (int i = 0; i < size; i++) {
key = arr[i]; // Store the current element as the key
j = i - 1; // Set the index for comparing with previous elements

// 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
}

// Place the key in its correct position


arr[j + 1] = key;

[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>

void print_array(int*, int);


void bubbleSort(int*, int);

int main(void) {
int arr[] = {5, 2, 8, 1, 9};
int n = sizeof(arr) / sizeof(arr[0]);

printf("Original array: ");


print_array(arr, n);
bubbleSort(arr, n);
printf("Sorted array: ");
print_array(arr, n);

return 0;
}

void print_array(int arr[], int size) {


for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

void bubbleSort(int arr[], int n) {


for (int i = 0; i < n - 1; i++) {
int swapped = 0; // Optimization: flag to check if swapping occurred
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// Swap elements
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = 1;

[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>

void print_array(int*, int);


void selectionSort(int*, int);

int main(void) {
int arr[] = {5, 2, 8, 1, 9};
int n = sizeof(arr) / sizeof(arr[0]);

printf("Original array: ");


print_array(arr, n);
selectionSort(arr, n);
printf("Sorted array: ");
print_array(arr, n);

return 0;
}

void print_array(int arr[], int size) {


for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}

void selectionSort(int arr[], int n) {


for (int i = 0; i < n - 1; i++) {
// Find the minimum element in the unsorted portion

[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.

2. Deletion (by value):


- If head is NULL:
- Return.
- If head contains the value:
- Update head to head->next.
- Else:
- Traverse the list while keeping track of the previous node.
- If current node's data matches the value:
- Update previous node's next to current node's next.

3. Search (for a value):


- Traverse the list.
- If current node's data matches the value:
- Return true.
- If the end of the list is reached:
- Return false.

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;

// Linked List structure


typedef struct LinkedList {
Node* head;
} LinkedList;

// Initialize the linked list


void initList(LinkedList* list) {
list->head = NULL;
}

// Create a new node


Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}

// Insert at the end


void insert(LinkedList* list, int data) {
Node* newNode = createNode(data);
if (!list->head) {
list->head = newNode;
} else {
Node* current = list->head;
while (current->next) {
current = current->next;
}

[12]
DSA Assignment
current->next = newNode;
}
}

// Delete a node by value


void delete(LinkedList* list, int value) {
if (!list->head) return;

if (list->head->data == value) {
Node* temp = list->head;
list->head = list->head->next;
free(temp);
return;
}

Node* current = list->head;


while (current->next && current->next->data != value) {
current = current->next;
}

if (current->next) {
Node* temp = current->next;
current->next = current->next->next;
free(temp);
}
}

// Display the linked list


void display(LinkedList* list) {
Node* current = list->head;
while (current) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}

// Main function for testing


int main() {
LinkedList list;
initList(&list);
insert(&list, 1);
insert(&list, 2);
insert(&list, 3);
display(&list);
delete(&list, 2);
display(&list);
return 0;
}

[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.

3. Search for a Value:


- Traverse the list, comparing each node's data to the search value.
- If found:
- Return True.
- Otherwise:
- Return False.

4. Reverse the List:

[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>

// Define the structure for the node


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

// Function to create a new node


struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}

// Function to insert a node at the end of the list


void insert(struct Node** head, int data) {
struct Node* newNode = createNode(data);
if (*head == NULL) { // If list is empty
*head = newNode;
return;
}
struct Node* last = *head;
while (last->next != NULL) { // Traverse to the last node
last = last->next;
}
last->next = newNode;
newNode->prev = last;
}

// Function to delete a node by value


void delete(struct Node** head, int value) {
struct Node* temp = *head;

// If the list is empty


if (temp == NULL) {
printf("List is empty\n");
return;
}

// If the node to be deleted is the head


if (temp != NULL && temp->data == value) {

[16]
DSA Assignment
*head = temp->next;
if (*head != NULL) {
(*head)->prev = NULL;
}
free(temp);
return;
}

// Traverse the list and search for the node to delete


while (temp != NULL && temp->data != value) {
temp = temp->next;
}

// If node is not found


if (temp == NULL) {
printf("Node with value %d not found\n", value);
return;
}

// Adjust the pointers to remove the node


if (temp->next != NULL) {
temp->next->prev = temp->prev;
}
if (temp->prev != NULL) {
temp->prev->next = temp->next;
}
free(temp);
}

// Function to search for a node by value


int search(struct Node* head, int value) {
struct Node* temp = head;
while (temp != NULL) {
if (temp->data == value) {
return 1; // Found
}
temp = temp->next;
}
return 0; // Not found
}

// Function to reverse the list


void reverse(struct Node** head) {
struct Node* temp = NULL;
struct Node* current = *head;

// Swap next and prev for each node


while (current != NULL) {
temp = current->prev;

[17]
DSA Assignment
current->prev = current->next;
current->next = temp;
current = current->prev;
}

// Update the head to the new first node


if (temp != NULL) {
*head = temp->prev;
}
}

// Function to display the list


void display(struct Node* head) {
if (head == NULL) {
printf("List is empty\n");
return;
}
struct Node* temp = head;
while (temp != NULL) {
printf("%d <-> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}

// Main function to test the doubly linked list


int main() {
struct Node* head = NULL;

// Insert nodes
insert(&head, 10);
insert(&head, 20);
insert(&head, 30);
insert(&head, 40);

printf("List after insertion:\n");


display(head);

printf("Searching for 20: %s\n", search(head, 20) ? "Found" : "Not Found");

// Delete a node
delete(&head, 20);
printf("List after deleting 20:\n");
display(head);

// Reverse the list


reverse(&head);
printf("List after reversal:\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.

2. Insertion at the Beginning:


- Create a new node.
- If the list is empty:
- Set the new node as 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.
- Update the new node's next to the current head.
- Set the new node as 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.

4. Search for a Value:


- Traverse the list starting from the head.
- If a node with the given value is found:
- Return True.
- If the entire list is traversed without finding the value:
- Return False.

5. Reverse the List:


- If the list is empty or has one node:
- No action is needed.
- Reverse the next pointers of all nodes.
- Update the head to the last node.
❖ Code:
#include <stdio.h>
#include <stdlib.h>

// Define the structure for the node


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

// Function to create a new node


struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = newNode; // Points to itself
return newNode;
}

// Function to insert a node at the end


void insert(struct Node** head, int data) {
struct Node* newNode = createNode(data);
if (!*head) {
*head = newNode;
} else {
struct Node* temp = *head;
while (temp->next != *head) temp = temp->next;
temp->next = newNode;
newNode->next = *head;
}
}

// Function to delete a node by value


void delete(struct Node** head, int value) {
if (!*head) return;

[21]
DSA Assignment

struct Node* temp = *head;


if (temp->data == value) {
if (temp->next == *head) {
free(temp);
*head = NULL;
} else {
while (temp->next != *head) temp = temp->next;
temp->next = (*head)->next;
free(*head);
*head = temp->next;
}
return;
}

struct Node* prev = NULL;


while (temp->data != value && temp->next != *head) {
prev = temp;
temp = temp->next;
}

if (temp->data == value) {
prev->next = temp->next;
free(temp);
}
}

// Function to search for a value


int search(struct Node* head, int value) {
if (!head) return 0;

struct Node* temp = head;


do {
if (temp->data == value) return 1;
temp = temp->next;
} while (temp != head);
return 0;
}

// Function to reverse the list


void reverse(struct Node** head) {
if (!*head || (*head)->next == *head) return;

struct Node *prev = NULL, *curr = *head, *next = NULL;


struct Node* last = *head;
do {
next = curr->next;
curr->next = prev;
prev = curr;

[22]
DSA Assignment
curr = next;
} while (curr != *head);

last->next = prev;
*head = prev;
}

// Function to display the list


void display(struct Node* head) {
if (!head) {
printf("List is empty\n");
return;
}

struct Node* temp = head;


do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != head);
printf("(head)\n");
}

int main() {
struct Node* head = NULL;

// Insert nodes
insert(&head, 10);
insert(&head, 20);
insert(&head, 30);
insert(&head, 40);
display(head);

// Search for a value


printf("Search 20: %s\n", search(head, 20) ? "Found" : "Not Found");

// Delete a node
delete(&head, 20);
display(head);

// Reverse the list


reverse(&head);
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>

// Define the structure for the stack node


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

// Function to create a new node


struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

[25]
DSA Assignment
newNode->data = data;
newNode->next = NULL;
return newNode;
}

// Function to push an element onto the stack


void push(struct Node** top, int data) {
struct Node* newNode = createNode(data);
newNode->next = *top; // Point new node to the current top
*top = newNode; // Update the top to the new node
printf("%d pushed onto the stack.\n", data);
}

// Function to pop an element from the stack


void pop(struct Node** top) {
if (*top == NULL) {
printf("Stack Underflow! No element to pop.\n");
return;
}
struct Node* temp = *top;
*top = (*top)->next; // Update top to the next node
printf("%d popped from the stack.\n", temp->data);
free(temp); // Free the popped node
}

// Function to peek at the top element of the stack


int peek(struct Node* top) {
if (top == NULL) {
printf("Stack is empty.\n");
return -1; // Indicating an empty stack
}
return top->data;
}

// Function to check if the stack is empty


int isEmpty(struct Node* top) {
return top == NULL;
}

// Main function to test stack operations


int main() {
struct Node* stack = NULL; // Initialize the stack

// Perform stack operations


push(&stack, 10);
push(&stack, 20);
push(&stack, 30);
printf("Top element is %d\n", peek(stack));

[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

// Define the stack structure


typedef struct {
int data[MAX_SIZE];
int top;
} Stack;

[28]
DSA Assignment
// Initialize the stack
void initialize(Stack* stack) {
stack->top = -1;
}

// Check if the stack is empty


int isEmpty(Stack* stack) {
return stack->top == -1;
}

// Check if the stack is full


int isFull(Stack* stack) {
return stack->top == MAX_SIZE - 1;
}

// Push an element onto the stack


void push(Stack* stack, int value) {
if (isFull(stack)) {
printf("Stack Overflow! Cannot push %d.\n", value);
return;
}
stack->data[++stack->top] = value;
printf("%d pushed onto the stack.\n", value);
}

// Pop an element from the stack


void pop(Stack* stack) {
if (isEmpty(stack)) {
printf("Stack Underflow! No element to pop.\n");
return;
}
printf("%d popped from the stack.\n", stack->data[stack->top--]);
}

// Peek at the top element of the stack


int peek(Stack* stack) {
if (isEmpty(stack)) {
printf("Stack is empty.\n");
return -1; // Indicating an empty stack
}
return stack->data[stack->top];
}

// Main function to test stack operations


int main() {
Stack stack;
initialize(&stack);

// Perform stack operations

[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: -

Perform Queue operations using Array and linked list implementation.

❖ 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

Linked List-Based Queue


1. Enqueue:
- Create newNode with value.
- If front == NULL: front = rear = newNode.
- Else: rear->next = newNode, rear = newNode.

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

// Define the queue structure


struct Queue {
int data[MAX_SIZE];
int front, rear;
};

// Initialize the queue


void initializeQueue(struct Queue* q) {
q->front = 0;
q->rear = -1;
}

// Check if the queue is empty


int isEmpty(struct Queue* q) {
return q->rear < q->front;
}

// Check if the queue is full


int isFull(struct Queue* q) {
return q->rear == MAX_SIZE - 1;
}

// Enqueue operation (add an element to the queue)


void enqueue(struct Queue* q, int value) {

[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);
}

// Dequeue operation (remove an element from the queue)


void dequeue(struct Queue* q) {
if (isEmpty(q)) {
printf("Queue Underflow! No element to dequeue.\n");
return;
}
printf("%d dequeued from the queue.\n", q->data[q->front++]);
}

// Peek operation (view the front element)


int peek(struct Queue* q) {
if (isEmpty(q)) {
printf("Queue is empty.\n");
return -1;
}
return q->data[q->front];
}

// Main function to test the queue operations


int main() {
struct Queue q;
initializeQueue(&q);

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:

Linked List-Based Queue Implementation:


#include <stdio.h>
#include <stdlib.h>

// Define the structure for the queue node


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

// Define the queue structure


struct Queue {
struct Node *front, *rear;
};

// Initialize the queue


void initializeQueue(struct Queue* q) {
q->front = q->rear = NULL;
}

// Check if the queue is empty


int isEmpty(struct Queue* q) {
return q->front == NULL;
}

// Enqueue operation (add an element to the queue)


void enqueue(struct Queue* q, int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = NULL;

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);
}

// Dequeue operation (remove an element from the queue)


void dequeue(struct Queue* q) {
if (isEmpty(q)) {
printf("Queue Underflow! No element to dequeue.\n");
return;
}
struct Node* temp = q->front;
q->front = q->front->next;

if (q->front == NULL) {
q->rear = NULL;
}

printf("%d dequeued from the queue.\n", temp->data);


free(temp);
}

// Peek operation (view the front element)


int peek(struct Queue* q) {
if (isEmpty(q)) {
printf("Queue is empty.\n");
return -1;
}
return q->front->data;
}

// Main function to test the queue operations


int main() {
struct Queue q;
initializeQueue(&q);

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.

3. Delete from Front:


- If front == NULL: print "Underflow", exit.
- Else: value = front->data, front = front->next.
- If front != NULL: front->prev = NULL.
- Else: rear = NULL.
- Free the removed node.

4. Delete from Rear:


- If rear == NULL: print "Underflow", exit.

[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>

// Define the structure of a deque node


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

// Define the structure of the deque


struct Deque {
struct Node* front;
struct Node* rear;
};

// Initialize the deque


void initializeDeque(struct Deque* dq) {
dq->front = dq->rear = NULL;
}

// Check if the deque is empty


int isEmpty(struct Deque* dq) {
return dq->front == NULL;
}

// Insert an element at the front


void insertFront(struct Deque* dq, int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = dq->front;
newNode->prev = NULL;

[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);
}

// Insert an element at the rear


void insertRear(struct Deque* dq, int value) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = value;
newNode->next = NULL;
newNode->prev = dq->rear;

if (isEmpty(dq)) {
dq->front = newNode;
} else {
dq->rear->next = newNode;
}
dq->rear = newNode;
printf("%d inserted at the rear.\n", value);
}

// Delete an element from the front


void deleteFront(struct Deque* dq) {
if (isEmpty(dq)) {
printf("Deque Underflow! Cannot delete from front.\n");
return;
}
struct Node* temp = dq->front;
printf("%d deleted from the front.\n", temp->data);

dq->front = dq->front->next;
if (dq->front == NULL) {
dq->rear = NULL;
} else {
dq->front->prev = NULL;
}
free(temp);
}

// Delete an element from the rear


void deleteRear(struct Deque* dq) {
if (isEmpty(dq)) {
printf("Deque Underflow! Cannot delete from rear.\n");
return;
}

[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);
}

// Peek the front element


void peekFront(struct Deque* dq) {
if (isEmpty(dq)) {
printf("Deque is empty.\n");
} else {
printf("Front element: %d\n", dq->front->data);
}
}

// Peek the rear element


void peekRear(struct Deque* dq) {
if (isEmpty(dq)) {
printf("Deque is empty.\n");
} else {
printf("Rear element: %d\n", dq->rear->data);
}
}

// Main function to test the deque operations


int main() {
struct Deque dq;
initializeDeque(&dq);

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.

3. Add Two Polynomials:


- Initialize p1, p2 (pointers to two polynomials), and result list.
- Traverse p1 and p2:
- If p1->exponent == p2->exponent:
- sumCoeff = p1->coefficient + p2->coefficient.
- Add newNode(sumCoeff, p1->exponent) to result.
- Advance p1, p2.
- If p1->exponent > p2->exponent:
- Add p1's term to result, advance p1.
- Else:
- Add p2's term to result, advance p2.
- Append remaining terms from p1 or p2 to result.

[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;
};

struct Node* createNode(int coef, int exp) {


struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->coefficient = coef;
newNode->exponent = exp;
newNode->next = NULL;
return newNode;
}

void insertNode(struct Node** head, int coef, int exp) {


struct Node* newNode = createNode(coef, exp);
if (*head == NULL || (*head)->exponent < exp) {
newNode->next = *head;
*head = newNode;
return;
}
struct Node* curr = *head;
while (curr->next && curr->next->exponent >= exp) curr = curr->next;
newNode->next = curr->next;
curr->next = newNode;
}

struct Node* addPolynomials(struct Node* p1, struct Node* p2) {


struct Node* result = NULL;
while (p1 || p2) {
if (p1 && (!p2 || p1->exponent > p2->exponent)) {
insertNode(&result, p1->coefficient, p1->exponent);
p1 = p1->next;
} else if (p2 && (!p1 || p2->exponent > p1->exponent)) {
insertNode(&result, p2->coefficient, p2->exponent);
p2 = p2->next;
} else {
int sum = p1->coefficient + p2->coefficient;
if (sum) insertNode(&result, sum, p1->exponent);
p1 = p1->next;
p2 = p2->next;
}

[43]
DSA Assignment
}
return result;
}

void displayPolynomial(struct Node* head) {


while (head) {
printf("%dx^%d", head->coefficient, head->exponent);
if (head->next) printf(" + ");
head = head->next;
}
printf("\n");
}

int main() {
struct Node* poly1 = NULL, *poly2 = NULL;
int n, coef, exp;

printf("Enter number of terms in first polynomial: ");


scanf("%d", &n);
printf("Enter terms (coefficient exponent):\n");
for (int i = 0; i < n; i++) {
scanf("%d %d", &coef, &exp);
insertNode(&poly1, coef, exp);
}

printf("Enter number of terms in second polynomial: ");


scanf("%d", &n);
printf("Enter terms (coefficient exponent):\n");
for (int i = 0; i < n; i++) {
scanf("%d %d", &coef, &exp);
insertNode(&poly2, coef, exp);
}

printf("First Polynomial: ");


displayPolynomial(poly1);
printf("Second Polynomial: ");
displayPolynomial(poly2);

struct Node* result = addPolynomials(poly1, poly2);


printf("Sum of Polynomials: ");
displayPolynomial(result);

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.

2. Insertion (Recursive and Iterative):


- Recursive:
- If tree is empty, create a new node as root.
- If value < current node, insert left; if >, insert right.
- Recursively move to left or right based on comparison.
- Iterative:
- Start at root, move left for smaller, right for larger values.
- Insert when an empty child is found.

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.

7. Level-by-Level Traversal (BFS):


- Use a queue, enqueue root.
- While queue is not empty, dequeue node, visit it, enqueue children.

8. Count Leaf and Non-Leaf Nodes:


- Leaf Nodes: Count nodes with no left or right children.
- Non-Leaf Nodes: Count nodes with at least one child.

9. Calculate Tree Height:

[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).

10. Create a Mirror Image:


- Swap left and right children for each node recursively, starting from root.
❖ Code:
#include <stdio.h>
#include <stdlib.h>

// Define structure for a node


struct Node {
int data;
struct Node* left;
struct Node* right;
};

// Function to create a new node


struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (!newNode) {
printf("Memory error\n");
return NULL;
}
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}

// 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;
}

// Search a node in the BST


struct Node* search(struct Node* root, int data) {
while (root != NULL) {
if (data == root->data) {
return root;
} else if (data < root->data) {
root = root->left;
} else {
root = root->right;
}
}
return NULL;
}

// Find minimum node in the BST (for deletion)


struct Node* findMin(struct Node* root) {
while (root->left != NULL) {
root = root->left;
}
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;
}

// Preorder Traversal (Recursive)


void preorderRecursive(struct Node* root) {
if (root == NULL) return;
printf("%d ", root->data);
preorderRecursive(root->left);
preorderRecursive(root->right);
}

// Postorder Traversal (Recursive)


void postorderRecursive(struct Node* root) {
if (root == NULL) return;
postorderRecursive(root->left);
postorderRecursive(root->right);
printf("%d ", root->data);
}

// Inorder Traversal (Recursive)


void inorderRecursive(struct Node* root) {
if (root == NULL) return;
inorderRecursive(root->left);
printf("%d ", root->data);
inorderRecursive(root->right);
}

// Preorder Traversal (Iterative)


void preorderIterative(struct Node* root) {
if (root == NULL) return;
struct Node* stack[100];
int top = -1;
stack[++top] = root;
while (top != -1) {
struct Node* current = stack[top--];

[50]
DSA Assignment
printf("%d ", current->data);
if (current->right) stack[++top] = current->right;
if (current->left) stack[++top] = current->left;
}
}

// Postorder Traversal (Iterative)


void postorderIterative(struct Node* root) {
if (root == NULL) return;

struct Node* stack1[100], * stack2[100]; // Declare two stacks


int top1 = -1, top2 = -1;

// Push root onto the first stack


stack1[++top1] = root;

// Traverse the tree


while (top1 != -1) {
struct Node* current = stack1[top1--];
stack2[++top2] = current; // Push onto the second stack

// 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;
}

// Print the elements from the second stack


while (top2 != -1) {
struct Node* current = stack2[top2--];
printf("%d ", current->data);
}
}

// Inorder Traversal (Iterative)


void inorderIterative(struct Node* root) {
if (root == NULL) return;
struct Node* stack[100];
int top = -1;
struct Node* current = root;
while (top != -1 || current != NULL) {
while (current != NULL) {
stack[++top] = current;
current = current->left;
}
current = stack[top--];
printf("%d ", current->data);
current = current->right;
}

[51]
DSA Assignment
}

// Level Order Traversal (Breadth-First Search)


void levelOrderTraversal(struct Node* root) {
if (root == NULL) return;
struct Node* queue[100];
int front = -1, rear = -1;
queue[++rear] = root;
while (front != rear) {
struct Node* current = queue[++front];
printf("%d ", current->data);
if (current->left) queue[++rear] = current->left;
if (current->right) queue[++rear] = current->right;
}
}

// Count Leaf and Non-Leaf Nodes


void countLeafAndNonLeaf(struct Node* root, int* leafCount, int* nonLeafCount) {
if (root == NULL) return;
if (root->left == NULL && root->right == NULL) {
(*leafCount)++;
} else {
(*nonLeafCount)++;
}
countLeafAndNonLeaf(root->left, leafCount, nonLeafCount);
countLeafAndNonLeaf(root->right, leafCount, nonLeafCount);
}

// Calculate the height of the tree


int height(struct Node* root) {
if (root == NULL) return -1;
int leftHeight = height(root->left);
int rightHeight = height(root->right);
return (leftHeight > rightHeight ? leftHeight : rightHeight) + 1;
}

// Create a mirror image of the tree


struct Node* mirror(struct Node* root) {
if (root == NULL) return NULL;
struct Node* temp = root->left;
root->left = root->right;
root->right = temp;
mirror(root->left);
mirror(root->right);
return root;
}

// 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);

printf("Inorder Traversal (Recursive): ");


inorderRecursive(root);
printf("\n");

printf("Preorder Traversal (Recursive): ");


preorderRecursive(root);
printf("\n");

printf("Postorder Traversal (Recursive): ");


postorderRecursive(root);
printf("\n");

printf("Inorder Traversal (Iterative): ");


inorderIterative(root);
printf("\n");

printf("Preorder Traversal (Iterative): ");


preorderIterative(root);
printf("\n");

printf("Postorder Traversal (Iterative): ");


postorderIterative(root);
printf("\n");

printf("Level Order Traversal: ");


levelOrderTraversal(root);
printf("\n");

int leafCount = 0, nonLeafCount = 0;


countLeafAndNonLeaf(root, &leafCount, &nonLeafCount);
printf("Leaf Nodes: %d, Non-Leaf Nodes: %d\n", leafCount, nonLeafCount);

printf("Height of the Tree: %d\n", height(root));

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).

2. Input Elements into stack1:


- Push all elements to be reversed into stack1.

3. Transfer Elements to stack2:


- While stack1 is not empty:
- Pop from stack1 and push the element into stack2.

4. Transfer Back to stack1:


- While stack2 is not empty:
- Pop from stack2 and push the element back into stack1.

5. Result:
- stack1 is now reversed compared to the original order.

6. Output the Reversed Stack:


- Print the elements of stack1 to verify the reversal.
❖ Code:
#include <stdio.h>
#include <stdlib.h>

// Define the structure for a stack


struct Stack {
int top;
int capacity;
int* array;
};

// Function to create a stack


struct Stack* createStack(int capacity) {
struct Stack* stack = (struct Stack*)malloc(sizeof(struct Stack));

[55]
DSA Assignment
stack->capacity = capacity;
stack->top = -1;
stack->array = (int*)malloc(stack->capacity * sizeof(int));
return stack;
}

// Function to check if the stack is empty


int isEmpty(struct Stack* stack) {
return stack->top == -1;
}

// Function to check if the stack is full


int isFull(struct Stack* stack) {
return stack->top == stack->capacity - 1;
}

// Function to push an element onto the stack


void push(struct Stack* stack, int data) {
if (isFull(stack)) {
printf("Stack overflow\n");
return;
}
stack->array[++stack->top] = data;
}

// Function to pop an element from the stack


int pop(struct Stack* stack) {
if (isEmpty(stack)) {
printf("Stack underflow\n");
return -1;
}
return stack->array[stack->top--];
}

// Function to display the elements of the stack


void display(struct Stack* stack) {
if (isEmpty(stack)) {
printf("Stack is empty\n");
return;
}
for (int i = stack->top; i >= 0; i--) {
printf("%d ", stack->array[i]);
}
printf("\n");
}

// Function to reverse the stack using an additional stack


void reverseStack(struct Stack* stack1) {
struct Stack* stack2 = createStack(stack1->capacity);

[56]
DSA Assignment

// Transfer elements from stack1 to stack2


while (!isEmpty(stack1)) {
push(stack2, pop(stack1));
}

// Transfer elements back from stack2 to stack1


while (!isEmpty(stack2)) {
push(stack1, pop(stack2));
}

free(stack2->array);
free(stack2);
}

// Main function
int main() {
int n, element;

printf("Enter the number of elements in the stack: ");


scanf("%d", &n);

struct Stack* stack = createStack(n);

printf("Enter the elements of the stack:\n");


for (int i = 0; i < n; i++) {
scanf("%d", &element);
push(stack, element);
}

printf("Original Stack: ");


display(stack);

reverseStack(stack);

printf("Reversed Stack: ");


display(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).

2. Input Elements into stack1:


- Push all elements to be reversed into stack1.

3. Transfer Elements to stack2:


- While stack1 is not empty:
- Pop from stack1 and push the element into stack2.

4. Transfer Back to stack1:


- While stack2 is not empty:
- Pop from stack2 and push the element back into stack1.

5. Result:
- stack1 is now reversed compared to the original order.

6. Output the Reversed Stack:


- Print the elements of stack1 to verify the reversal.
❖ Code:
#include <stdio.h>
#include <stdlib.h>

// Define structure for stack


struct Stack {
int data[100];
int top;
};

[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;
}

// Push element onto stack


void push(struct Stack* stack, int value) {
stack->data[++(stack->top)] = value;
}

// Pop element from stack


int pop(struct Stack* stack) {
return stack->data[(stack->top)--];
}

// Check if stack is empty


int isStackEmpty(struct Stack* stack) {
return stack->top == -1;
}

// Initialize queue
void initQueue(struct Queue* queue) {
queue->front = 0;
queue->rear = -1;
}

// Enqueue element to queue


void enqueue(struct Queue* queue, int value) {
queue->data[++(queue->rear)] = value;
}

// Dequeue element from queue


int dequeue(struct Queue* queue) {
return queue->data[(queue->front)++];
}

// Check if queue is empty


int isQueueEmpty(struct Queue* queue) {
return queue->front > queue->rear;
}

// Function to reverse a stack using an additional queue


void reverseStackUsingQueue(struct Stack* stack) {

[60]
DSA Assignment
struct Queue queue;
initQueue(&queue);

// Transfer elements from stack to queue


while (!isStackEmpty(stack)) {
enqueue(&queue, pop(stack));
}

// Transfer elements back from queue to stack


while (!isQueueEmpty(&queue)) {
push(stack, dequeue(&queue));
}
}

// Function to display stack elements


void displayStack(struct Stack* stack) {
for (int i = stack->top; i >= 0; i--) {
printf("%d ", stack->data[i]);
}
printf("\n");
}

// Main function
int main() {
struct Stack stack;
initStack(&stack);

int n, value;
printf("Enter the number of elements in the stack: ");
scanf("%d", &n);

printf("Enter the elements of the stack:\n");


for (int i = 0; i < n; i++) {
scanf("%d", &value);
push(&stack, value);
}

printf("Original Stack: ");


displayStack(&stack);

reverseStackUsingQueue(&stack);

printf("Reversed Stack: ");


displayStack(&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.

I am also deeply grateful to my family, whose unwavering support and


understanding have been a pillar of strength during the course of this work. Their
patience with my long hours of study and their encouragement when I faced
difficulties allowed me to stay focused and motivated. They have always stood by me,
offering both practical and emotional support, for which I am truly appreciative.

Lastly, I would like to acknowledge the broader academic community and


resources that have played a role in this assignment. The numerous online tutorials,
forums, and textbooks on C programming have provided additional clarity and insight,
reinforcing my understanding of key concepts and helping me troubleshoot coding
issues along the way.

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]

You might also like