September 8, 2024

DSA

Data Structures and Algorithm
Share :

DSA Question and Answer


(Suggest: Find the question by search page)

a).Discuss the need of AVL Tree and Write the step-by-step construct the AVL tree for the following data: 1,5,6,8,3,2,4,7,2,3,4,8,7,6,5,11,10,12.

Answer.

AVL Tree

  • AVL Trees are Self-Balanced Binary Search Trees.
  • In AVL trees, the balancing factor of each node is either 0 or 1 or -1.
  • Balance Factor of AVL Tree calculated as = Height of Left Sub-tree – Height of Right Sub-tree

Construction of AVL Trees –

  • Insertion Operation is performed to construct the AVL Tree.
  • Inserting the element in the AVL tree is same as the insertion performed in BST.
  • After insertion, check the balance factor of each node of the resulting tree.
    • After the insertion, the balance factor of each node is either 0 or 1 or -1, then the tree is considered to be balancedconcludes the operation, and inserts the next element if any.
    • After the insertion, the balance factor of at least one node is not 0 or 1 or -1, then the tree is considered to be imbalancedperform the suitable rotation to balance the tree, and after the tree is balanced, insert the next element if any.

Rotations used to Balance the AVL Tree –

  • After inserting an element in the AVL tree,
  • If a tree becomes imbalanced, then there exists one particular node in the tree by balancing which the entire tree becomes balanced automatically.
  • To rebalance the tree, balance that particular node.

To find that particular node:

  • Traverse the path from the newly inserted node to the root node.
  • Check the balance factor of each node that is encountered while traversing the path.
  • The first encountered imbalanced node will be the node that needs to be balanced.

To balance that node:

  • Count three nodes in the direction of the leaf node.
  • Then, use the concept of AVL Tree Rotations to rebalance the tree.
    • LL Rotation – In LL rotation, every node moves one position to left from the current position.
    • RR Rotation – In RR rotation, every node moves one position to right from the current position.
    • LR Rotation – In LR rotation, at first, every node moves one position to the left and then one position to right from the current position.
    • RL Rotation – In RL rotation, at first every node moves one position to right and then one position to left from the current position.

Computer Organization & Architecture Q&A : Click Here


b. Explain Brute Force Algorithm with an example in detail

Answer

Brute force algorithm is a simple, yet often effective, approach to solve problems by checking all possible solutions through exhaustive search. This algorithm involves evaluating every possible solution, and then selecting the one that satisfies the problem’s constraints and provides the best result.

Here’s an example to illustrate how the brute force algorithm works:
Suppose you want to find the optimal path from point A to point B on a map with many possible routes. You know the distances between each pair of adjacent cities, and your goal is to find the shortest path that connects A to B.

Step 1: List all the possible routes from A to B. Suppose we have the following cities: A, B, C, D, and E. Here are all the possible routes from A to B:
A -> B
A -> C -> B
A -> C -> D -> B
A -> E -> B
A -> C -> E -> B
A -> E -> C -> B
A -> D -> C -> B
A -> D -> E -> B
A -> E -> D -> B

Step 2: Compute the distances of all possible routes Suppose the distances between adjacent cities are:
A to B = 10
A to C = 5
C to D = 2
C to E = 4
D to B = 3
E to B = 5
D to C = 1
E to C = 2
E to D = 3

Using this information, we can compute the distances of all possible routes:
A -> B = 10
A -> C -> B = 9
A -> C -> D -> B = 11
A -> E -> B = 15
A -> C -> E -> B = 11
A -> E -> C -> B = 12
A -> D -> C -> B = 8
A -> D -> E -> B = 11
A -> E -> D -> B = 13

Step 3: Select the shortest route From the above list, we can see that the shortest route from A to B is A -> C -> B, with a distance of 9.

As we can see, the brute force algorithm involves checking all possible solutions to a problem to find the optimal one. Although this approach can be time-consuming, it guarantees that the solution we obtain is the best possible one, given the constraints of the problem. However, for very large problems, the brute force algorithm may not be practical or efficient.

Computer Organization & Architecture Q&A : Click Here


Which is the best algorithm that covered as part of your course would recommend finding single source shortest path (SSSP) and why?

Answer

  • One of the best algorithms for finding single source shortest path (SSSP) is Dijkstra’s algorithm. It is a very efficient algorithm that works well on weighted graphs where all edge weights are non-negative.
  • The main advantage of Dijkstra’s algorithm is its speed. It has a time complexity of O(E + V log V), where E is the number of edges and V is the number of vertices in the graph. This makes it one of the fastest algorithms for finding the shortest path between two nodes in a graph.
  • Another advantage of Dijkstra’s algorithm is that it is guaranteed to find the shortest path. This is because it uses a greedy approach to explore the graph, always choosing the node with the smallest distance from the source node. Once a node has been explored, its distance is fixed and will not change, so there is no need to revisit it.
  • Overall, Dijkstra’s algorithm is a very efficient and reliable algorithm for finding single source shortest path in a weighted graph with non-negative edge weights.

Here is an implementation of Dijkstra’s algorithm in Python:

import heapq

def dijkstra(graph, start):
# initialize distances and visited nodes
distances = {node: float('inf') for node in graph}
distances[start] = 0
visited = set()

# create heap queue for nodes to be explored
heap = [(0, start)]

while heap:
# get node with smallest distance
(distance, node) = heapq.heappop(heap)

# check if node has been visited
if node in visited:
continue

# add node to visited set
visited.add(node)

# update distances for adjacent nodes
for neighbor, weight in graph[node].items():
new_distance = distances[node] + weight
if new_distance < distances[neighbor]:
distances[neighbor] = new_distance
heapq.heappush(heap, (new_distance, neighbor))

return distances

This code takes in a weighted graph in the form of a dictionary, where each key is a node and each value is another dictionary representing the neighboring nodes and their weights. The ‘start’ argument specifies the source node for the shortest path calculation.

The algorithm uses a heap queue to keep track of the nodes to be explored, with the node with the smallest distance always at the top of the queue. The distances for each node are initialized to infinity, except for the source node which is set to 0. As the algorithm explores each node, it updates the distances for its neighbors if a shorter path is found.

Computer Organization & Architecture Q&A : Click Here


A file contains the following character with the frequencies as shown. If Huffman coding is used for data compression, determine

1) Huffman Code for each character
2) Average code length

Characters – Frequencies
C – 30
A – 15
T – 10
T – 10
L – 4
E – 12
S – 18

Answer.

To construct the Huffman code for data compression, we need to follow these steps:

Step 1: Sort the characters in order of increasing frequency.
L – 4
T – 10
T – 10
A – 15
E – 12
S – 18
C – 30

Step 2: Merge the two characters with the lowest frequency into a single node, assigning the sum of their frequencies as the weight of the node.
L – 4
T – 10
T – 10
A – 15
E – 12
S – 18
C – 30

LT – 14
A – 15
E – 12
S – 18
C – 30

Step 3: Repeat step 2, until all the characters are merged into a single node.
L – 4
LT – 14
A – 15
ES – 30
C – 30

L – 4
A – 15
LT – 14
C – 30
ES – 30

L – 4
A – 15
C – 30
LTES – 44

Step 4: Assign 0 to the left branch and 1 to the right branch of each node.
L – 0
A – 10
C – 11
LTES – 3

Step 5: Write the Huffman code for each character by tracing the path from the root node to the leaf node.
L – 00
A – 101
C – 100
T – 01
E – 110
S – 111

Therefore, the Huffman code for each character is:
L – 00
A – 101
C – 100
T – 01
E – 110
S – 111

Calculate the average code length by multiplying the frequency of each character by the length of its Huffman code, adding up these values, and dividing by the total frequency.
Average code length = (4 x 2 + 15 x 3 + 30 x 3 + 10 x 2 + 12 x 3 + 18 x 3) / (4 + 15 + 30 + 10 + 12 + 18) = 2.74 bits per symbol

Therefore, the average code length is 2.74 bits per symbol.

Computer Organization & Architecture Q&A : Click Here


a. Which is the best algorithm that covered as part of your course would recommend finding single source shortest path (SSSP) and why?

b. Write the algorithm and work out with detailed steps using chosen algorithm to find SSSG?

c. What are the limitations of the chosen algorithm and advantages?

d. Provide Average, Best- and worst-case time complexities?

Answer:

a. One of the best algorithms for finding Single Source Shortest Path (SSSP) is Dijkstra’s Algorithm. This algorithm is widely used due to its simplicity, efficiency, and effectiveness in finding the shortest path from a single source to all other nodes in a weighted graph with non-negative edge weights.

b. Here’s the step-by-step algorithm to find the SSSP using Dijkstra’s algorithm:

* Initialize the distance from the source node to all other nodes as infinity, except for the source node itself, which is 0.
* Initialize a priority queue and add the source node with a priority of 0.
* While the priority queue is not empty, do the following:
* Extract the node with the lowest priority from the queue.
* For each neighbor of the extracted node, do the following:
-> Calculate the tentative distance from the source node to the neighbor node, which is the distance from the source node to the extracted node plus the weight of the edge connecting them.
-> If the tentative distance is less than the current distance from the source node to the neighbor node, update the distance and add the neighbor node to the priority queue with its updated priority.
-> Once all nodes have been visited, the distance to each node from the source node will have been calculated and stored in an array.

Here’s an example of working out the algorithm for the following graph, with the source node as node A:

Example :
2
A —– B
|            |
|             | 3
C —– D
1

  • Initialize the distance array: dist[A] = 0, dist[B] = ∞, dist[C] = ∞, dist[D] = ∞.
  • Add node A to the priority queue with priority 0.
  • Extract node A with priority 0.
  • Update the distance to node B: dist[B] = 2.
  • Add node B to the priority queue with priority 2.
  • Extract node B with priority 2.
  • Update the distance to node D: dist[D] = 5.
  • Update the distance to node C: dist[C] = 5.
  • Add nodes C and D to the priority queue with priorities 5.
  • Extract node C with priority 5.
  • Extract node D with priority 5.The algorithm is complete, and the final distance array is: dist[A] = 0, dist[B] = 2, dist[C] = 5, dist[D] = 5.

c. One limitation of Dijkstra’s algorithm is that it only works with non-negative edge weights. If there are negative edge weights, the algorithm may not produce the correct result. Additionally, Dijkstra’s algorithm does not work well with large graphs as it has a time complexity of O(V^2) when implemented with an adjacency matrix, and O(E log V) when implemented with a priority queue and adjacency list. An advantage of the algorithm is that it guarantees the shortest path to each node from the source node.

d. The time complexity of Dijkstra’s algorithm depends on the implementation. Using an adjacency matrix, the worst-case time complexity is O(V^2). Using a priority queue and adjacency list, the worst-case time complexity is O(E log V). In the best-case scenario, where the source node is connected only to a few nodes, the time complexity is O(E log V). In the average case, the time complexity is O(E log V), but this can vary depending on the structure of the graph.

Computer Organization & Architecture Q&A : Click Here


 

Assume that a singly linked list consisting of ‘n’ number of nodes and each node has Data (Integer Numeric) and Link Field. Write the code swapping the data in the List.

Answer

To swap the data of two nodes in a singly linked list, we need to identify the nodes that contain the data to be swapped and then swap their data values. Here’s an example code in Python:

class Node:
def __init__(self, data=None):
self.data = data
self.next = None

class LinkedList:
def __init__(self):
self.head = None

def swap_data(self, x, y):
if x == y:
return

# Find the first node
prev_x = None
curr_x = self.head
while curr_x and curr_x.data != x:
prev_x = curr_x
curr_x = curr_x.next

# Find the second node
prev_y = None
curr_y = self.head
while curr_y and curr_y.data != y:
prev_y = curr_y
curr_y = curr_y.next

# Check if both nodes exist in the list
if not curr_x or not curr_y:
return

# Swap the data
if prev_x:
prev_x.next = curr_y
else:
self.head = curr_y

if prev_y:
prev_y.next = curr_x
else:
self.head = curr_x

temp = curr_x.next
curr_x.next = curr_y.next
curr_y.next = temp

def print_list(self):
curr = self.head
while curr:
print(curr.data, end=' ')
curr = curr.next
print()

# Example usage
my_list = LinkedList()
my_list.head = Node(1)
my_list.head.next = Node(2)
my_list.head.next.next = Node(3)
my_list.head.next.next.next = Node(4)
my_list.head.next.next.next.next = Node(5)

print("Original List:")
my_list.print_list()

my_list.swap_data(2, 4)

print("List after swapping data:")
my_list.print_list()

For More Updates Join Our Channels :