Hemanth Summer Internship
Hemanth Summer Internship
Summer Internship
A training report
Submitted to
PHAGWARA, PUNJAB
SUBMITTED BY
1|Page
Annexure-II: Student Declaration
Dated: 25-08-2024
2|Page
ACKNOWLEDGEMENT
Primarily I would like to thank God for being able to learn a new technology. Then I
would like to express my special thanks of gratitude to the teacher and instructor of the
course Mastering Data Structures : Theory to practice who provide me the golden
opportunity to learn a new technology from home.
I would like to also thank my own college Lovely Professional University for offering
such a course which not only improve my programming skill but also taught me other
new technology.
Then I would like to thank my parents and friends who have helped me with their
valuable suggestions and guidance for choosing this course.
Last but not the least I would like to thank my all classmates who have helped me a lot.
[Hemanth Chowdary]
[12209061]
3|Page
INTERNSHIP CERTIFICATE
4|Page
TABLE OF CONTENTS
1 COVER PAGE 1
3 ACKNOWLEDGEMENT 3
5 INTRODUCTION 6-8
7 THE CONTENT 11 - 47
8 THE PROJECT
9 CONCLUSION
10 BIBLIOGRAPHY 52
5|Page
INTRODUCTION OF THE PROJECT UNDERTAKEN
Scope of work
6|Page
Importance and Applicabilities
1. Performance Optimization:
Understanding different data structures (like arrays, trees, and graphs) and
algorithms (like sorting, searching, and dynamic programming) allows developers
to approach problems in a structured manner. For instance, using a graph traversal
algorithm can solve network-related problems more efficiently than brute-force
methods.
3. Memory Efficiency:
Proper use of data structures helps in optimizing memory usage. For example, a
hash table may be used for constant-time lookups, while a tree-based structure can
be used when ordering is important. This helps in conserving memory, especially
in memory-constrained environments like embedded systems or mobile
applications.
Programs that implement efficient data structures and algorithms can scale to
handle larger datasets or more complex operations. As the volume of data
increases (e.g., in big data applications), selecting the right algorithms ensures
that the system remains responsive and efficient.
7|Page
Role and profile
• Assisted in the development and testing of projects where data structures played a key
role.
Profile:
8|Page
BRIEF DESCRITION OF WORKDONE
2. Text Editors:
• Used simple text editors such as Notepad++ or Sublime Text for writing and organizing
code snippets during the implementation of data structures.
Data analysis
• Complexity Analysis: Conducted theoretical and practical analysis of time and space
complexity for each data structure implemented.
10 | P a g e
INTRODUCTION TO DATA STRUCTURES AND ALGORITHMS:
DataStructures:
Data structures are ways of organizing and storing data in a
computer so that it can be accessed and modified efficiently. They
provide a framework for managing large amounts of data, enabling
the efficient performance of various operations like insertion,
deletion, and search. Common data structures include arrays, linked
lists, stacks, queues, trees, graphs, and hash tables.
Algorithms:
An algorithm is a step-by-step procedure or a set of rules followed
in calculations or other problem-solving operations. Algorithms
take inputs, process them through various data structures, and
produce desired outputs. Some well-known algorithms include
sorting (e.g., quicksort, mergesort), searching (e.g., binary search),
and graph traversal (e.g., depth-first search).
Together, data structures and algorithms form the foundation of
computer science and programming, facilitating efficient data
management and problem-solving.
11 | P a g e
Importance of Data Structures and Algorithms in
Programming
Time Complexity:
Time complexity is a me assure of the amount of time an algorithm
takes to complete as a function of the size of the input. It helps
predict how an algorithm's execution time increases with the input
size. For example, a linear time complexity (O(n)) means that if the
input size doubles, the time required will also double. Common
time complexities include O(1) (constant time), O(n) (linear time),
O(n²) (quadratic time), and O(log n) (logarithmic time).
Space Complexity:
Space complexity refers to the amount of memory or space an
algorithm requires relative to the size of the input data. It accounts
for all the memory used, including the input data, auxiliary space
for variables, and function calls. Efficient algorithms should
optimize space usage, especially in memory-constrained
environments.
12 | P a g e
Both time and space complexity are critical in determining the
performance of algorithms, ensuring that programs run quickly and
efficiently even with large datasets.
Big O (O)Notation:
Big O notation is used to describe the worst-case time or space
complexity of an algorithm, providing an upper bound on the
algorithm’s growth rate. It tells us the maximum amount of time or
space that the algorithm will require, regardless of the input size.
For example, O(n) means the time required grows linearly with the
input size, while O(1) means the time required is constant, no
matter the input size.
Omega (Ω)Notation:
Omega notation provides the lower bound for the time complexity
of an algorithm. It describes the best-case scenario or the minimum
time an algorithm will take to complete. For example, Ω(n) means
that, at the very least, the algorithm will take linear time.
Theta (Θ)Notation:
Theta notation provides a tight bound on the time complexity of an
algorithm. It means that the algorithm’s performance will always be
within a certain range, bounded both above and below. For
example, Θ(n) indicates that the algorithm will take linear time in
both the worst and best cases.
These notations help developers evaluate and compare the
efficiency of different algorithms, enabling informed decisions
about which algorithms to use based on the specific requirements
and constraints of a problem.
13 | P a g e
ARRAYS AND LINKED LISTS:
Introduction to Arrays
An array is a data structure that stores a collection of elements (values or variables), each
identified by an array index or key. The elements are stored in contiguous memory
locations, and this direct, sequential storage enables fast and efficient access to any
element using its index.
Basic Operations:
Access: Accessing any element in an array is a simple and constant time operation
(`O(1)`), because each element's position is calculated as an offset from the base address
of the array.
Insertion:
At the End: Inserting an element at the end of the array takes `O(1)` time if there's
sufficient space.
Deletion:
At the End: Deletion of the last element takes constant time `O(1)`.
At the Beginning or Middle: Similar to insertion, deletion requires shifting elements
and takes `O(n)` time.
Search:
Linear Search: Searching for an element by scanning the array takes `O(n)`.
Binary Search: If the array is sorted, binary search can be used to find an element in
`O(log n)`.
14 | P a g e
Advantages:
Fast Access: Because arrays use indexed access, reading or modifying an element is
extremely fast.
Predictable Memory Usage: Since the size of an array is fixed at the time of its
creation, memory allocation is predictable and efficient.
Cache Friendly: Due to the contiguous nature of arrays, they are cache-friendly and
can lead to better performance with respect to modern CPU architectures.
Limitations:
Fixed Size: Arrays cannot change size once defined, leading to possible
wasted memory or insufficient space.
15 | P a g e
Introduction to Linked Lists
A linked list is a linear data structure where each element is a separate object called a node.
Each node contains two fields: one for storing the data and the other for storing a reference
(or pointer) to the next node in the sequence. Unlike arrays, linked lists do not store elements
in contiguous memory locations, and their size can grow or shrink dynamically as elements
are added or removed.
16 | P a g e
2. Doubly Linked List:
Each node has two pointers: one pointing to the next node and one pointing to the
previous node. This allows traversal in both forward and backward directions.
Basic Operations:
Insertion:
At the Head: Inserting a node at the beginning of the list is `O(1)` since it only involves
updating pointers.
At the Tail: Inserting at the tail can also be efficient if a tail pointer is maintained
(`O(1)`); otherwise, it requires traversal (`O(n)`).
In the Middle: Inserting into the middle involves traversing to the desired location
(`O(n)`) and updating pointers.
Deletion:
At the Head: Deleting the first node is `O(1)`.
In the Middle or End: Deleting nodes requires traversal to find the node to be deleted
(`O(n)`).
17 | P a g e
Traversal: Traversal of a linked list always takes `O(n)` time since elements cannot be
accessed directly by index.
Advantages:
Dynamic Size: Linked lists can easily grow or shrink in size as needed. No need to pre-
allocate memory.
Limitations:
Sequential Access: Accessing an element requires traversing the list from the head,
leading to `O(n)` time complexity.
Memory Overhead: Every node requires additional memory for storing a pointer to
the next node (or previous in doubly linked lists).
Size: Arrays have a fixed size determined at the time of declaration, while linked lists
can dynamically adjust their size.
Access: Arrays provide constant-time O(1) access to elements via indexing, whereas
linked lists provide sequential access with O(n) complexity.
Memory: Arrays require a block of contiguous memory, whereas linked lists allocate
memory dynamically and can operate on fragmented memory.
Overhead: Linked lists require extra memory for pointers, while arrays have a lower
overhead since no pointers are required.
18 | P a g e
Conclusion:
Arrays and linked lists each have their unique strengths and weaknesses, making them
suited to different types of problems. Arrays are ideal for scenarios where fast, random
access to elements is critical, and the size of the data is known ahead of time. In contrast,
linked lists excel in situations where frequent insertions and deletions are required, and
the data size may fluctuate unpredictably.
19 | P a g e
STACKS, QUEUES AND RECURSION:
Introduction to Stacks
A stack is a linear data structure that follows the Last In, First Out (LIFO) principle. This
means the last element added is the first one to be removed.
Operations:
Push: Adds an element to the top of the stack.
Implementation:
Array-Based Stack: Uses a fixed-size array to store elements. Simple but limited by the
array's capacity.
Linked List-Based Stack: Uses nodes with pointers to dynamically allocate memory.
This allows unlimited size but requires additional memory for pointers.
20 | P a g e
Applications:
Function Call Management: The call stack manages function calls in programming,
storing local variables and return addresses.
Undo Mechanism: In text editors or games, stacks are used to implement undo
functionality.
Expression Evaluation: In compilers, stacks help evaluate expressions and parse syntax
trees.
Introduction to Queues:
A queue is a linear data structure that follows the First In, First Out (FIFO) principle,
meaning the first element added is the first one to be removed.
Operations:
Enqueue: Adds an element to the end (rear) of the queue.
Implementation:
21 | P a g e
Array-Based Queue: Can be implemented using a circular array to avoid shifting
elements.
Linked List-Based Queue: Uses nodes for dynamic memory allocation, avoiding size
limitations.
Applications:
CPU Scheduling: Queues manage processes in operating systems.
Breadth-First Search (BFS): Queues are fundamental to the BFS algorithm used in
graph traversal.
Introduction to Recursion:
Recursion is a technique where a function calls itself to solve a problem. Recursive solutions
often break the problem down into smaller, similar subproblems until reaching a base case that
can be solved directly.
Basic Concepts:
Base Case: The condition that stops the recursion. Without a base case, recursion would
result in infinite calls.
22 | P a g e
Recursive Case: The part of the function where it calls itself to work on a smaller or
simpler instance of the problem.
Examples:
Factorial: n! = n * (n-1)!, where factorial(0) = 1 is the base case.
Fibonacci Sequence: F(n) = F(n-1) + F(n-2), with base cases F(0) = 0 and F(1) = 1.
Recursion:
Concept: Solves a problem by breaking it down into smaller instances of the same
problem, requiring function calls.
Memory Usage: Requires more memory due to the function call stack.
Code Structure: Generally more elegant and concise for certain problems like tree
traversals.
Iteration:
Concept: Repeats a process by looping through the elements until a condition is met.
Memory Usage: More efficient in memory usage since no additional function calls are
required.
Code Structure: Can be more complex for problems that are naturally recursive, like
backtracking or divide and conquer.
def factorial(n):
if n == 0:
return 1
else:
23 | P a g e
return n * factorial(n - 1)
Iterative:
def factorial(n):
result = 1
result *= i
return result
Conclusion:
Stacks and queues are fundamental data structures used in various real-world applications, from
CPU scheduling to managing undo operations. Recursion, a powerful tool for solving problems,
often provides a simpler approach compared to iteration but comes with the trade-off of higher
memory usage due to the call stack. Understanding these concepts is critical for tackling
complex programming challenges.
24 | P a g e
TREES AND BALANCED TREES:
Introduction to Trees:
Node: The fundamental unit of a tree that contains data and may link to other nodes
(children).
Root: The topmost node of the tree, which has no parent.
Parent: A node that has one or more children.
Child: A node that is directly connected to another node when moving away from the
root.
Sibling: Nodes that share the same parent.
Leaf Node: A node that has no children; it is the endpoint of a path in the tree.
Internal Node: A node with at least one child.
Subtree: A portion of the tree that itself is a tree, consisting of a node and all of its
descendants.
Height: The length of the longest path from the root to a leaf.
Depth: The distance from the root to a particular node.
Level: All nodes at the same depth are said to be on the same level.
Properties:
Acyclic: Trees contain no cycles (loops).
Connected: There is exactly one path between any two nodes.
Hierarchy: Trees naturally represent hierarchical structures where one element leads to
one or more dependent elements.
25 | P a g e
Binary Trees:
A binary tree is a special type of tree in which each node has at most two children,
typically referred to as the left and right child.
Properties:
Complete Binary Tree: All levels are fully filled except possibly the last level, which is
filled from left to right.
Full Binary Tree: Every node has 0 or 2 children, i.e., no nodes have only one child.
Perfect Binary Tree: A full binary tree where all leaf nodes are at the same level, and
every level is fully filled.
Balanced Binary Tree: A binary tree where the height of the two child subtrees of any
node difference by not more than one.
Basic Operations:
1. Insertion: Adding a node to a binary tree involves finding the appropriate position based
on a specific criterion (e.g., level-order for completeness).
2. Deletion:
26 | P a g e
Leaf Deletion: Simply remove the node.
One Child Deletion: Replace the node with its child.
Two Children Deletion: Replace the node with its in-order successor or
predecessor.
3. Traversal:
In order (LNR): Visit left subtree, node, then right subtree.
Preorder (NLR): Visit node, then left subtree, then right subtree.
Post order (LRN): Visit left subtree, then right subtree, then node.
Level-order: Traverse the tree level by level from top to bottom.
A binary search tree (BST) is a binary tree where nodes are arranged in a specific order:
for each node, all elements in the left subtree are smaller, and all elements in the right
subtree are larger.
Properties:
27 | P a g e
Sorted Structure: This property allows efficient searching, insertion, and deletion
operations.
Uniqueness: Typically, no two nodes have the same value (to maintain the binary search
property).
Dynamic: Can grow and shrink as elements are added or removed.
Basic Operations:
1. Search:
Efficiently finds a node by comparing values. The time complexity is O(log n) in
a balanced tree but can degrade to O(n) in an unbalanced tree.
2. Insertion:
Inserting a new node involves traversing the tree until the correct position is
found that maintains the binary search property.
3. Deletion:
Leaf Node: Simply remove the node.
Node with One Child: Replace the node with its child.
Node with Two Children: Replace with its in-order successor (the smallest node
in the right subtree) or in-order predecessor (the largest node in the left subtree).
Advantages:
Efficient Search: Provides faster search times than unsorted structures like linked lists.
Order: Maintains elements in a sorted order, making in-order traversal ideal for
producing sorted data.
Limitations:
Unbalanced Trees: When nodes are inserted in sorted order, BSTs can become skewed,
degrading performance to O(n).
28 | P a g e
Balanced Binary Trees:
Balanced binary trees are binary trees that automatically adjust their structure to ensure
that operations like search, insertion, and deletion maintain a logarithmic time complexity
(O(log n)).
29 | P a g e
Balanced Trees and AVL Trees:
An AVL tree is a self-balancing binary search tree where the heights of the left and right
subtrees of any node differ by no more than one. AVL trees are named after their
inventors, Adelson and Landis.
Properties:
Balance Factor: For any node, the height difference between the left and right subtree
should be at most ±1.
Self-Balancing: After each insertion or deletion, the tree performs rotations to restore
balance.
Time Complexity: Operations like search, insertion, and deletion are guaranteed to be O
(log n) in an AVL tree.
Rotations:
Right Rotation: Performed when the tree becomes unbalanced due to heavy left subtree
(left-left case).
Left Rotation: Performed when the tree becomes unbalanced due to heavy right subtree
(right-right case).
Left-Right Rotation: Combination of left rotation followed by right rotation, used in
left-right imbalance.
Right-Left Rotation: Combination of right rotation followed by left rotation, used in
right-left imbalance.
Operations in AVL Trees:
Insertion:
Insertions follow the same rules as a binary search tree. After inserting a node, if
the balance factor becomes out of range (±1), rotations are performed to restore
balance.
Deletion:
Similar to insertion, after deleting a node, the tree checks the balance factors of all
affected nodes and performs rotations if needed.
30 | P a g e
Search:
Searching in an AVL tree is efficient, with a time complexity of O(log n), as the
tree remains balanced.
Advantages:
Consistent Performance: Ensures that all basic operations maintain logarithmic time
complexity, even in the worst case.
Sorted Structure: Like other binary search trees, AVL trees maintain sorted order,
making them useful for ordered data.
Limitations:
Higher Overhead: The balancing operations increase the complexity and runtime of
insertion and deletion operations slightly compared to unbalanced BSTs.
More Complex Implementation: AVL trees are more complex to implement due to the
need for rotations and balance factor maintenance.
31 | P a g e
Conclusion:
Trees and balanced trees are essential data structures in computer science due to their
hierarchical nature and efficiency in operations like searching, insertion, and deletion. Binary
trees provide the foundation, while binary search trees enhance searching efficiency. Balanced
binary trees, such as AVL trees, ensure that operations remain efficient even under worst-case
scenarios by maintaining a balanced structure through rotations. This combination of properties
makes them ideal for use in databases, search engines, and many real-time applications.
Graphs are a versatile data structure used to represent a set of objects and their relationships.
A graph is defined by two main components: vertices (or nodes) and edges (or links). Graphs
can be either directed (where the edges have a direction) or undirected (where the edges have
no direction). They can also be weighted (where each edge has a weight or cost associated
with it) or unweighted.
Key Concepts:
Vertex (Node): A fundamental unit of the graph that stores data or represents an entity.
Edge (Link): A connection between two vertices, representing the relationship between
them.
Degree: The number of edges incident on a vertex. In directed graphs, there are in-
degree (number of incoming edges) and out-degree (number of outgoing edges).
33 | P a g e
Path: A sequence of edges connecting two vertices.
Cycle: A path that starts and ends at the same vertex without repeating any edge.
Graph Representation:
1. Adjacency Matrix:
A 2D matrix where rows and columns represent vertices. An entry at position (i,
j) is 1 if there is an edge between vertex i and vertex j, otherwise, it is 0.
2. Adjacency List:
An array of lists where each index corresponds to a vertex, and the list at that
index contains all the vertices it is connected to by edges.
3. Edge List:
34 | P a g e
A list of all the edges in the graph, each edge represented as a pair (or triplet if
weighted) of vertices.
Cons: Inefficient for most graph operations like searching for adjacent vertices.
Graph traversal algorithms are used to visit all the vertices and edges of a graph. The two
primary traversal techniques are Breadth-First Search (BFS) and Depth-First Search (DFS).
BFS explores the graph level by level. Starting from a source node, it first visits
all the neighbouring nodes at the current level before moving to the next level.
Implementation: BFS uses a queue to keep track of the nodes to be visited next.
Applications:
Time Complexity: O(V + E), where V is the number of vertices and E is the
number of edges.
DFS explores the graph by going as deep as possible along each branch before
backtracking. It uses a stack (or recursion) to keep track of the visited nodes.
Applications:
36 | P a g e
Heap Data Structure:
A Heap is a complete binary tree where each node satisfies the heap property. The heap
property ensures that for a Max-Heap, the value of each node is greater than or equal to the
values of its children, and for a Min-Heap, the value of each node is smaller than or equal to
the values of its children.
Types of Heaps:
1. Min-Heap:
The smallest element is at the root, and each parent node is smaller than its
children. This structure is useful for implementing priority queues.
Use Cases: Dijkstra's algorithm for finding the shortest path, priority queues.
2. Max-Heap:
37 | P a g e
The largest element is at the root, and each parent node is larger than its children.
This structure is used in algorithms like heapsort.
Heap Operations:
1. Insertion:
Insert a new element at the end of the heap and then "bubble up" (or "heapify up")
the element to maintain the heap property (O(log n) time complexity).
38 | P a g e
Remove the root (smallest or largest element) and replace it with the last element.
Then, "bubble down" (or "heapify down") the new root to restore the heap
property (O(log n)).
3. Peek:
Simply return the root element (min or max) without modifying the heap. This
operation takes constant time O(1).
4. Heapify:
The process of transforming a binary tree into a heap. This can be done
in O(n) time.
Applications of Heaps:
Priority Queues: Heaps are the basis for efficiently implementing priority queues.
Sorting Algorithms: Heapsort uses the heap structure to sort elements in O(n log n) time.
39 | P a g e
Hashing:
Hashing is a technique used to efficiently store and retrieve data by mapping it to a location
in a table using a hash function. The primary goal of hashing is to achieve constant time
complexity O(1) for insertions, deletions, and lookups.
Hash Functions:
A hash function maps an input (key) to a fixed-size integer (hash value). Ideally, the hash
function distributes keys uniformly across the hash table to minimize collisions.
Efficient computation.
Applications of Hashing:
Caching: Hash tables are used in cache systems to store frequently accessed data for
faster retrieval.
40 | P a g e
Cryptography: Hash functions are fundamental to cryptographic algorithms, used in
hashing passwords, digital signatures, and data integrity checks.
Compiler Design: Symbol tables in compilers are implemented using hash tables for fast
lookups of variable names, constants, and functions.
Conclusion:
The topics of graphs, heaps, and hashing are central to many areas of computer science.
Graphs model complex relationships between data points, while traversal algorithms like
BFS and DFS allow us to explore and analyze these connections. Heaps provide efficient
priority handling and are critical to algorithms like heapsort and scheduling. Hashing delivers
fast and efficient data retrieval, making it indispensable in database systems, cryptography,
and other applications. Understanding these structures and their operations is key to
developing efficient software solutions.
41 | P a g e
SEARCHING, SORTING AND PROJECT:
Searching Algorithms:
1. Linear Search:
Description: This is the simplest searching algorithm that checks each element in
the array sequentially until the desired element is found or the entire array has
been searched.
Time Complexity: O(n) in the worst and average cases, where n is the number of
elements in the array.
Space Complexity: O(1) since no additional space is required.
Use Case: Best used when the array is unsorted or for small datasets.
2. Binary Search:
Description: Binary Search works on a sorted array by repeatedly dividing the
search interval in half. It compares the target value with the middle element of the
array and eliminates half of the remaining elements from consideration.
Time Complexity: O(log n) in the worst and average cases.
Space Complexity: O(1) for iterative implementation, O(log n) for recursive
implementation due to stack space.
Use Case: Efficient for large, sorted datasets.
42 | P a g e
Sorting Algorithms:
1. Bubble Sort:
Description: A simple comparison-based sorting algorithm that repeatedly steps
through the list, compares adjacent elements, and swaps them if they are in the
wrong order.
Time Complexity: O(n^2) in the worst and average cases.
Space Complexity: O(1).
Use Case: Suitable for small datasets or when the list is almost sorted.
43 | P a g e
Selection Sort:
Description: This algorithm divides the array into a sorted and unsorted part,
repeatedly selecting the smallest (or largest) element from the unsorted part and
moving it to the sorted part.
Time Complexity: O(n^2) in the worst and average cases.
Space Complexity: O(1).
Use Case: Best for small arrays and when memory is a constraint.
2. Insertion Sort:
Description: Builds the sorted array one item at a time by repeatedly picking the
next element and inserting it into its correct position among the already sorted
elements.
Time Complexity: O(n^2) in the worst case, but O(n) for nearly sorted arrays.
Space Complexity: O(1).
Use Case: Efficient for small or nearly sorted arrays.
44 | P a g e
3. Merge Sort:
Description: A divide-and-conquer algorithm that divides the array into halves,
recursively sorts each half, and then merges the sorted halves.
Time Complexity: O(n log n) in all cases.
Space Complexity: O(n) due to the use of temporary arrays during merging.
Use Case: Suitable for large datasets and when stability is important.
45 | P a g e
Quick Sort:
Description: Another divide-and-conquer algorithm that selects a "pivot" element
and partitions the array into two sub-arrays, such that elements less than the pivot
come before it and elements greater than the pivot come after. The process is
recursively applied to the sub-arrays.
Time Complexity: O(n log n) on average, but O(n^2) in the worst case.
Space Complexity: O(log n) due to recursion.
Use Case: Often the fastest general-purpose sorting algorithm for large datasets,
despite its worst-case behaviour.
Time Complexity: Refers to the amount of time an algorithm takes to run as a function
of the size of the input. It's essential for comparing the efficiency of algorithms. For
example:
Linear Search: O(n) for searching an unsorted list.
46 | P a g e
Binary Search: O(log n) for a sorted list.
Merge Sort: O(n log n) for guaranteed efficiency, regardless of input.
Bubble Sort/Insertion Sort/Selection Sort: O(n^2) for worst and average cases.
Space Complexity: Refers to the amount of memory an algorithm uses relative to the
input size.
Linear and Binary Search: Both have O(1) space complexity, with no additional
memory required.
Merge Sort: Requires O(n) space due to additional storage needed for merging.
Quick Sort: Uses O(log n) space due to the recursion stack.
47 | P a g e
CHAPTER-3 THE PROJECT:
Source code:
#include <iostream>
#include <vector>
#include <string>
int main() {
vector<string> todoList;
int choice;
string task;
while (true) {
cout << "\n1. Add Task\n2. View List\n3. Delete Task\n4. Exit\nChoose an option: ";
cin >> choice;
cin.ignore(); // Ignore newline left in buffer
if (choice == 1) {
cout << "Enter task: ";
getline(cin, task);
todoList.push_back(task);
} else if (choice == 2) {
for (size_t i = 0; i < todoList.size(); ++i)
cout << i + 1 << ". " << todoList[i] << "\n";
} else if (choice == 3) {
48 | P a g e
cout << "Enter task number to delete: ";
int taskNumber;
cin >> taskNumber;
if (taskNumber > 0 && taskNumber <= todoList.size())
todoList.erase(todoList.begin() + taskNumber - 1);
else
cout << "Invalid task number.\n";
} else if (choice == 4) {
break;
} else {
cout << "Invalid choice. Please try again.\n";
}
}
49 | P a g e
Output of the code executed:
50 | P a g e
Conclusion:
The development of the To-Do List Manager has been a rewarding experience,
providing practical exposure to key programming concepts such as data structures,
user interface design, and file handling. This project effectively showcases the use of
arrays and linked lists to store and manage tasks, and demonstrates an intuitive
approach to implementing core operations such as adding, editing, deleting, and
marking tasks as completed.
51 | P a g e
Through this project, I gained a deeper understanding of the importance of efficient
data organization and user experience design. Additionally, handling various edge cases,
such as ensuring data persistence across sessions and maintaining a flexible user
interface, allowed me to strengthen my problem-solving skills.
In conclusion, the To-Do List Manager successfully meets the goals of task management,
providing a simple and user-friendly platform for users to organize their daily activities.
This project has laid a solid foundation for future enhancements, such as integrating
advanced features like task prioritization, reminders, and synchronization across devices,
making it a valuable learning experience that bridges theoretical knowledge with
practical implementation.
Bibliography:
Mark Allen Weiss – "Data Structures and Algorithm Analysis in C++" (4th Edition,
2014)
Robert Lafore – "Data Structures and Algorithms in Java/C++" (2nd Edition, 2002)
52 | P a g e
Websites:
https://www.geeksforgeeks.org/data-structures/
https://www.learncpp.com/
https://www.tutorialspoint.com/data_structures_algorithms/index.
53 | P a g e