DSA2
DSA2
=>
A linear data structure is one in which elements are stored in a sequential or linear
manner. The data elements are arranged in such a way that there is a single line of
processing. Stacks are a prime example of a linear data structure.
Stack
Stacks follow the Last In, First Out (LIFO) principle, meaning the last element
added is the first one to be removed.
Operations in a Stack:
1. Push (element): Adds an element to the top of the stack.
2. Pop(): Removes the element from the top of the stack and returns it.
3. Peek/Top(): Returns the element at the top of the stack without removing it.
Height: The number of edges from the root to the farthest leaf.
Depth: The number of edges from the root to a particular node.
Operations in a Tree:
1. Insert(): Adds a node to the tree.
4. Traversal: Visits all nodes in a tree in a specific order. Common tree traversal
methods are:
o Pre-order Traversal
o In-order Traversal
o Post-order Traversal
Inserting a node into a linked list involves adding a new node at a specific position in
the list. A linked list is made up of nodes, where each node contains data and a
reference (or link) to the next node in the list. There are three types of node insertion
in a linked list:
Inserting a node at the beginning of the list means that the new node becomes the
head of the list, and the current head becomes the second node.
Steps:
2. Set the new node's next pointer to the current head of the list.
Inserting a node at the end means that the new node is added after the last node of
the list. If the list is empty, the new node becomes the head.
Steps:
3. Set the next pointer of the last node to the new node.
4. The new node’s next pointer will be nullptr, indicating it is the last node.
3. Insertion at a Specific Position
Inserting a node at a specific position means that you insert the new node between
two existing nodes. The position is typically specified by an index.
Steps:
2. Traverse the list to find the node before the desired position.
3. Set the next pointer of the new node to the next pointer of the previous node.
4. Set the next pointer of the previous node to the new node.
=> Reversing a linked list involves changing the direction of the links between the
nodes so that the last node becomes the first and the first node becomes the last.
This operation is useful in various applications, such as processing data in reverse
order or reversing the sequence of elements in a list.
There are several methods to reverse a linked list, but the most commonly used and
efficient method is to reverse the list iteratively. Below, I'll explain the iterative
approach to reverse a singly linked list, and provide an example in C/C++.
A circular linked list is a variation of a singly linked list where the last node's next
pointer points back to the first node, forming a circular chain of nodes. Unlike a singly
linked list, where the last node’s next is nullptr (indicating the end of the list), in a
circular linked list, the next pointer of the last node points to the first node, creating a
loop.
o To insert at the end, we traverse the list to the last node and change its
next pointer to the new node.
o The new node’s next pointer is then set to the first node, completing
the circle.
2. Insertion at the Beginning:
o Insert a new node at the beginning and set the new node’s next to the
current head.
o Traverse the list to the last node and update its next pointer to the new
node to maintain the circular structure.
3. Traversal:
o Start from the head and keep traversing using the next pointer until you
reach the head again (since it’s a circle).
4. Deletion:
o Deletion requires adjusting the next pointer of the previous node to
remove the target node and maintaining the circular structure.
A queue is a linear data structure that follows the First In First Out (FIFO) principle,
meaning the element that is added first is the one that gets removed first. The two
primary operations for a queue are enqueue (to add an element) and dequeue (to
remove an element). Queues are highly useful in scenarios where the order of
processing or execution matters and tasks must be processed in the same order in
which they arrive.
1. Scheduling Algorithms (CPU Scheduling)
In operating systems, queues are commonly used for scheduling processes. When
multiple processes are waiting for CPU time, they are placed in a queue. The Round-
Robin Scheduling Algorithm is a typical example where processes are assigned a
fixed time slot to execute
Example: In time-sharing systems, multiple processes share the CPU by
executing for a set amount of time in a circular fashion. A queue helps to
manage this order.
2. Print Queue
In environments with multiple users sending print jobs to a printer, a print queue is
maintained. Print jobs are added to the queue in the order they are received, and the
printer processes them one by one.
Example: When several users print documents to a shared printer, the print
queue ensures the order of the jobs is maintained and processed in FIFO.
3. Task Scheduling in Real-Time Systems
Web servers often handle multiple client requests concurrently. These requests are
placed in a queue, and the server processes them one by one. This ensures that the
server doesn’t get overloaded and that each request is handled in the order it was
received.
Example: When a web server receives multiple client requests, they are
queued up, and the server processes each request in the order they arrived,
ensuring fair access.
=> A tree is a hierarchical data structure that consists of nodes connected by edges.
It is a collection of elements, where each element (node) has a parent-child
relationship with other elements.
The root is the topmost node in the tree, and it does not have a parent.
Nodes represent the data in the tree and can have child nodes, except for the
leaf nodes (which are the nodes with no children).
Edges are the connections between nodes.
A binary tree is a type of tree where each node has at most two children,
often referred to as the left child and the right child.
Binary Search Trees (BST) for Searching:
Efficient searching: Binary Search Trees are widely used for searching
operations, such as searching for an element in a collection. Their average
time complexity is O(log n), making them efficient for large datasets.
Text Searching and Autocompletion: Tries are used in text search and
retrieval applications. A trie is useful in implementing auto-completion in
search engines or for dictionary lookups.
=> A binary tree is a tree data structure made up of nodes also known as left and
right nodes-each of which has a maximum of two offspring. The tree starts at the root
node.
Q.9 a) Differentiate depth first search and breadth first search technique in
detail.
=>
Conceptual BFS builds the tree level by DFS builds the tree sub-tree by
Difference level. sub-tree.
Repeatedly steps through the list, compares adjacent elements, and swaps
them if they are in the wrong order. The process repeats until the list is sorted.
Repeatedly selects the smallest (or largest) element from the unsorted part of
the list and swaps it with the first unsorted element.
Builds the final sorted array one item at a time by inserting each element into
its correct position in the already sorted part of the list.
A divide-and-conquer algorithm that splits the list into halves, recursively sorts
each half, and then merges the sorted halves.
Time Complexity: O(n log n)
Space Complexity: O(n)
Quick Sort:
Converts the list into a binary heap and then repeatedly extracts the maximum
(or minimum) element to build the sorted array.
4. Combine the results (no actual combining is necessary since the array is
sorted in place).
4. Divide-and-Conquer:
5. Tail Recursion:
Function calls: Stacks are used to keep track of the return addresses of
function calls, allowing the program to return to the correct location after a
function has finished executing.
Recursion: Stacks are used to store the local variables and return addresses
of recursive function calls, allowing the program to keep track of the current
state of the recursion.