Ilovepdf Merged
Ilovepdf Merged
CAMPUS
RATHINAM TECHZONE
EACHANARI, COIMBATORE-641021.
NAME :
REGISTER NUMBER :
YEAR/SEMESTER :
ACADEMIC YEAR :
RATHINAM TECHNICAL CAMPUS
RATHINAM TECHZONE
EACHANARI, COIMBATORE-641021.
BONAFIDE CERTIFICATE
NAME :
ACADEMIC YEAR :
YEAR/SEMESTER :
BRANCH :
Certified that this is the bonafide record of work done by the above student in the
EXPT NO :
DATE : Implement Binary tree
Create a Python program that implements a binary tree data structure. The program should take
dynamic input from the user to build the tree. Each input will represent a node, and you need to insert
it into its appropriate position within the binary tree structure. You don't need to implement any
specific tree traversal algorithms for this task; just focus on the insertion logic.
Example:
Sample Input: 1
5
24135
Sample Output: 1
Sample Input: 2
8
42613578
Sample Output: 2
Sample Input: 3
10
8 4 12 2 6 10 14 1 3 5 7 9 11 13 15
Sample Output: 3
Input Format:
The first line of input indicates the number of nodes. Subsequent lines contain space-separated integer
values representing the nodes.
Output Format:
The program should print 'Tree structure successfully built!' upon successful creation of the binary
tree.
Register No: 23105050
Constraints:
Input will always be valid, and the first number represents the total number of nodes to be inserted.
Duplicate values are allowed in the tree.
Hint:
Use a class to represent a node in the binary tree. Each node should have data, left child, and right
child attributes. Implement an insert method to add new nodes, adhering to the properties of a binary
search tree.
Naming Conventions:
Follow Python naming conventions - use CamelCase for class names and lowercase_with_underscores
for variables and methods.
Solution
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
class BinaryTree:
def __init__(self):
self.root = None
def main():
bt = BinaryTree()
n = int(input())
nodes = list(map(int, input().split()))
for node in nodes:
bt.insert(node)
print("Tree structure successfully built!")
Register No: 23105050
if __name__ == "__main__":
main()
Analysis:
EXPT NO :
DATE : Implement Binary Search tree
Imagine you are building a library management system. You need to store book records efficiently so
that searching for a specific book by its ID is fast. Implement a Binary Search Tree in Python to store
book records (represented by unique integer IDs) dynamically based on user input. Your program
should handle insertion of new book IDs and display the tree's inorder traversal, which represents the
sorted order of book IDs.
Example:
Sample Input: 1
5
10
5
15
2
7
Sample Output: 1
2 5 7 10 15
Sample Input: 2
8
50
30
70
20
40
60
80
10
Sample Output: 2
10 20 30 40 50 60 70 80
Sample Input: 3
9
8
3
10
Register No: 23105050
1
6
14
4
7
13Sample Output: 3
1 3 4 6 7 8 10 13 14
Input Format:
The first line contains an integer 'n' representing the number of book IDs. The following 'n' lines each
contain a single integer representing a book ID.
Output Format:
Constraints:
The input will consist of positive integers representing book IDs. Assume all book IDs are unique.
Hint:
Use a class to represent a node in the BST and implement methods for insertion and inorder traversal.
Naming Conventions:
Use descriptive variable names like 'root' for the root of the tree, 'data' for the node's value, 'left' and
'right' for child nodes.
Solution
class Node:
def __init__(self, data):
self.data=data
self.left=None
self.right=None
class BT_S:
def __init__(self):
self.root = None
def insert(self,data):
Newnode=Node(data)
if self.root is None:
self.root=Newnode
else:
self.temp=self.root
while(True):
if data<=self.temp.data:
if self.temp.left is not None:
self.temp=self.temp.left
else:
Register No: 23105050
self.temp.left=Newnode
return
elif data >= self.temp.data:
if self.temp.right is not None:
self.temp=self.temp.right
else:
self.temp.right=Newnode
return
def printInOrder(self,node):
if node is None:
return
self.printInOrder(node.left)
print(node.data,end=" ")
self.printInOrder(node.right)
def printPreOrder(self,node):
if node is None:
return
print(node.data,end=" ")
self.printPreOrder(node.left)
self.printPreOrder(node.right)
def printPostOrder(self,node):
if node is None:
return
self.printPostOrder(node.left)
self.printPostOrder(node.right)
print(node.data,end=" ")
bst=BT_S()
size=int(input())
for i in range(size):
data = int(input())
bst.insert(data)
bst.printInOrder(bst.root)
Analysis:
Implement a double-ended queue (deque) data structure in Python using a list as the underlying
storage mechanism. Your implementation should handle dynamic input, meaning users can add or
remove elements from both ends of the queue. The program should support the following operations:
1. `append(value)`: Adds an element to the rear of the deque. 2. `appendleft(value)`: Adds an element
to the front of the deque. 3. `pop()`: Removes and returns the element at the rear of the deque. Raises
an exception if the deque is empty. 4. `popleft()`: Removes and returns the element at the front of the
deque. Raises an exception if the deque is empty. 5. `peek()`: Returns the element at the rear of the
deque without removing it. Raises an exception if the deque is empty. 6. `peekleft()`: Returns the
element at the front of the deque without removing it. Raises an exception if the deque is empty. 7.
`is_empty()`: Returns `True` if the deque is empty, `False` otherwise. 8. `size()`: Returns the number
of elements in the deque.
`0Example:
Sample Input: 1
5
append 1
append 2
appendleft 0
peekleft
pop
Sample Output: 1
0
2
Sample Input: 2
4
append 10
appendleft 20
pop
size
Sample Output: 2
10
1
Sample Input: 3
Register No: 23105050
3
appendleft 30
peekleft
size
Sample Output: 3
30
Input Format:
The first line of input indicates the number of operations to be performed. Subsequent lines each
contain a single operation followed by its input (if any), separated by a space.
Output Format:
For each 'peek', 'pop', 'popleft', or 'size' operation, output the result on a new line. If an operation
results in an error, output the error message.
Constraints:
Hint:
Utilize the list methods `append()`, `insert()`, `pop()`, and `pop(0)` to efficiently implement the deque
operations. Remember to handle edge cases like popping from an empty deque.
Naming Conventions:
Solution
class Queue:
def __init__(self):
self.arr=[]
def enrear(self,val):
return self.arr.append(val)
def derear(self):
return self.arr.pop()
def enfront(self,val):
return self.arr.insert(0,val)
def defront(self):
return self.arr.pop(0)
def rearpeek(self):
return self.arr[-1]
def frontpeek(self):
return self.arr[0]
def display(self):
print(len(self.arr))
Register No: 23105050
res=Queue()
n=int(input())
for i in range(n):
oper=input().split()
if len(oper)>=2:
operation=oper[0]
val=int(oper[1])
else:
operation=oper[0]
if operation=='append':
r= res.enrear(val)
elif operation=='appendleft':
res.enfront(val)
elif operation=='pop':
r=res.derear()
print(r)
elif operation=='popleft':
r=res.defront()
print(r)
elif operation=='peek':
r=res.rearpeek()
print(r)
elif operation=='peekleft':
r=res.frontpeek()
print(r)
elif operation=='size':
res.display()
Analysis:
Imagine you're organizing a social network where users can be friends. Your task is to represent this
network efficiently using an adjacency list in Python. Each person will be a node in our graph, and a
friendship between two people will be represented by an edge. An adjacency list is a way to store this
information by using a dictionary: the keys are the nodes, and the value associated with each key is a
list of nodes directly connected to it (its neighbors). Your goal is to write a Python program that allows
you to add users (nodes) and friendships (edges) to this social network graph. Since it's an undirected
graph, if User A is friends with User B, then User B is also friends with User A.
Example:
Sample Input: 1
3
AddNode 0
AddNode 1
AddEdge 0 1
Sample Output: 1
Sample Input: 2
5
AddNode 0
AddNode 1
AddEdge 0 1
AddNode 2
AddEdge 1 2
Sample Output: 2
Sample Input: 3
8
AddNode 0
AddNode 1
AddNode 2
AddEdge 0 1
Register No: 23105050
AddEdge 1 2
AddNode 3
AddEdge 0 3
AddEdge 1 3
Sample Output: 3
Input Format:
The input will consist of multiple lines. The first line contains an integer 'N' representing the number
of operations. The following 'N' lines will each contain an operation, either 'AddNode x' (where x is
the node value) or 'AddEdge x y' (where x and y are the nodes to connect).
Output Format:
The output should be a string representation of the adjacency list, with nodes as keys and their
corresponding neighbor lists as values, enclosed in curly braces '{}'.
Constraints:
Assume input nodes are non-negative integers. 'AddEdge' should handle the undirected nature of the
graph.
Hint:
Use a dictionary in Python where keys represent nodes and values are lists of adjacent nodes.
Implement 'AddNode' to add keys and 'AddEdge' to update adjacency lists.
Naming Conventions:
Use descriptive variable names like 'graph', 'node', 'neighbor' for better code readability.
Solution
graph={}
def AddNode(node):
if node not in graph:
graph[node]=[]
def AddEdge(node1,node2):
AddNode(node1)
AddNode(node2)
graph[node1].append(node2)
graph[node2].append(node1)
for i in range(int(input())):
op=input().split()
if op[0]=="AddNode":
AddNode(int(op[1]))
Register No: 23105050
else:
AddEdge(int(op[1]), int(op[2]))
print(graph)
Analysis:
You are tasked with implementing a Python program that performs Breadth-First Search (BFS) on a
graph. Your program should take a graph represented as an adjacency list and a starting node as input.
The goal is to traverse the graph level by level from the starting node, visiting all reachable nodes.
Example:
Sample Input: 1
4
12
13
24
1
Sample Output: 1
1234
Sample Input: 2
7
12
13
24
25
36
37
1
Sample Output: 2
1234567
Sample Input: 3
10
12
13
24
35
36
Register No: 23105050
47
58
69
7 10
1
Sample Output: 3
1 2 3 4 5 6 7 8 9 10
Input Format:
The input consists of multiple lines. The first line contains an integer 'V' representing the number of
vertices in the graph. The subsequent 'V' lines each contain two space-separated integers 'u' and 'v',
indicating an edge between nodes 'u' and 'v'. The last line contains an integer representing the starting
node.
Output Format:
Print the nodes in the order they are visited during the BFS traversal, separated by spaces.
Constraints:
Hint:
Use a queue to store nodes at each level and mark visited nodes to avoid cycles.
Naming Conventions:
Solution
from collections import deque
while queue:
current_node = queue.popleft()
visited.append(current_node)
return visited
Register No: 23105050
num_vertices=int(input())
graph = {i: [] for i in range(1, num_vertices+1)}
for i in range(num_vertices-1):
key, value = map(int, input().split())
graph[key].append(value)
graph[value].append(key)
start_node=int(input())
bfs_result=breadth_first_search(graph, start_node)
print(" ".join(map(str, bfs_result)))
Analysis:
EXPT NO :
DATE : Implement Graph Traversal Tech
Imagine you're navigating a maze. You can only move forward until you hit a dead end, then you must
backtrack and try another path. This is the essence of Depth First Search (DFS). Your challenge is to
write a Python program that performs DFS on a graph, represented using an adjacency list. Given a
starting node, your program should explore the graph as far as possible along each branch before
backtracking.
Example:
Sample Input: 1
55
01
02
13
14
24
0
Sample Output: 1
01342
Sample Input: 2
67
01
02
13
14
25
35
45
0
Sample Output: 2
013524
Sample Input: 3
76
01
02
Register No: 23105050
13
24
35
46
0
Sample Output: 3
0135246
Input Format:
The first line contains two integers V and E separated by space, representing the number of vertices
and edges in the graph. The next E lines each contain two integers u and v, representing an edge
connecting vertex u and v. The last line contains a single integer, the starting node for DFS.
Output Format:
Print the nodes in the order they are visited during the DFS traversal separated by space.
Constraints:
The graph will have at most 100 nodes (0-indexed). Input edges will be valid and non-directional.
Hint:
Use a stack (or recursion) to keep track of the nodes to visit. Mark visited nodes to avoid cycles.
Naming Conventions:
Solution
def depth_first_search(graph, start_node):
visited=set()
stack=[start_node]
visit_order=[]
while stack:
current_node=stack.pop()
if current_node not in visited:
visited.add(current_node)
visit_order.append(current_node)
return visit_order
Register No: 23105050
v, e = input().split()
v, e = int(v), int(e)
graph={i: [] for i in range(v)}
for i in range(e):
u, v = map(int, input().split())
graph[u].append(v)
graph[v].append(u)
start_node=int(input())
dfs_traversal= depth_first_search(graph, start_node)
print(" ".join(map(str, dfs_traversal)))
Analysis:
EXPT NO :
DATE : Implement Dijkstra’s Algorithm.
Implement Dijkstra's algorithm to find the shortest path between two nodes in a graph. The graph will
be represented as an adjacency list, where each key is a node and its value is a list of its neighbors and
the corresponding edge weights. You need to return the shortest distance from the source node to the
destination node. If there is no path between the source and destination node, return -1.
Example:
Sample Input: 1
4412113423234314
Sample Output: 1
Sample Input: 2
5612214123325443245315
Sample Output: 2
Sample Input: 3
6712513224134335646456216
Sample Output: 3
Input Format:
The first line contains two integers, N and M, representing the number of nodes and edges,
respectively. The next M lines contain three integers each, representing an edge between two nodes
and its weight. The last line contains two integers, representing the source and destination nodes.
Output Format:
An integer representing the shortest distance between the source and destination nodes, or -1 if no path
exists.
Register No: 23105050
Constraints:
1 <= number of nodes <= 10^5, 1 <= number of edges <= 10^5, 1 <= edge weight <= 10^4
Hint:
Use a priority queue to keep track of the nodes with the shortest distances from the source node.
Naming Conventions:
Variable names should be descriptive and follow Python conventions (e.g., use snake_case).
Solution
import heapq
import sys
from collections import defaultdict
while priority_queue:
current_distance, current_node=heapq.heappop(priority_queue)
if current_node==destination:
return current_distance
if current_distance>shortest_distances[current_node]:
continue
for neighbor, weight in graph[current_node]:
distance=current_distance+weight
if distance<shortest_distances[neighbor]:
shortest_distances[neighbor]=distance
heapq.heappush(priority_queue, (distance, neighbor))
return -1
input_data=input().strip().split()
index=0
n=int(input_data[index]); index+=1
m=int(input_data[index]); index+=1
graph = defaultdict(list)
for i in range(m):
u=int(input_data[index]); index+=1
v=int(input_data[index]); index+=1
weight=int(input_data[index]); index+=1
graph[u].append((v, weight))
graph[v].append((u, weight))
source=int(input_data[index]); index+=1
destination=int(input_data[index])
Register No: 23105050
Analysis:
Implement a Python program that handles hash collisions in a hash table using open addressing with
both linear probing and quadratic probing techniques. **Open Addressing** Open addressing is a
method of collision resolution in hash tables. In open addressing, all elements are stored in the hash
table itself. So at any point, the size of the table must be greater than or equal to the total number of
keys. When a new element is to be inserted, the hash table is examined, starting with the hashed-to slot
and proceeding in some probe sequence, until an unoccupied slot is found. **Linear Probing** Linear
probing is a scheme used in open addressing for resolving collisions in hash tables. In linear probing,
we linearly search for the next empty slot in the table. **Quadratic Probing** Instead of using a
constant "skip" value like linear probing, quadratic probing uses a quadratic function to calculate the
skip value based on the number of attempts made to find an empty slot.
Example:
Sample Input: 1
8
10
20
30
40
50
60
70
80
Sample Output: 1
60
30
70
Sample Input: 2
10
23
43
12
78
54
87
98
11
32
45
Sample Output: 2
Sample Input: 3
12
5
15
Register No: 23105050
25
35
45
55
65
75
85
95
105
115
Sample Output: 3
Input Format:
The first line of input represents the number of elements to be inserted into the hash table. Subsequent
lines will contain the elements themselves.
Output Format:
Print the hash table content after inserting all the elements using both Linear Probing and Quadratic
Probing. Each element should be printed on a new line along with its index.
Register No: 23105050
Constraints:
1 <= Number of Inputs <= 10^5 0 <= Each input element <= 10^9
Hint:
For Linear Probing: h(x, i) = (h'(x) + i) % m For Quadratic Probing: h(x, i) = (h'(x) + i*i) % m where,
h'(x) is the hash function, i is the attempt number (starting from 0), and m is the size of the hash table.
Naming Conventions:
Solution
size=int(input(""))
elements=[]
print("")
for i in range(size):
elements.append(int(input()))
def linear_probing(hash_table,element):
index=element%size
i=1
while hash_table[index] is not None:
index=(index+i)%size
i+=1
hash_table[index]=element
def quadratic_probing(hash_table,element):
index=element%size
i=1
while hash_table[index] is not None:
index=(index+i*i)%size
i+=1
hash_table[index]=element
hash_table_linear=[None]*size
hash_table_quadratic=[None]*size
print("Hash Table using Linear Probing: ")
for element in elements:
linear_probing(hash_table_linear,element)
for i in range(size):
print(f"{hash_table_linear[i]} ")
print("\nHash Table using Quadratic Probing: ")
for element in elements:
quadratic_probing(hash_table_quadratic,element)
for i in range(size):
print(f"{hash_table_quadratic[i]} ")
Analysis:
You need to implement a Stack Abstract Data Type (ADT) using a Linked List in Python. Your
program should handle a dynamic number of inputs. The Stack ADT should support the following
operations:
2. **Pop ():** Removes and returns the element at the top of the stack. If the stack is empty, it should
indicate an error (e.g., return a specific message or raise an exception).
3. **Peek():** Returns the element at the top of the stack without removing it. If the stack is empty,
handle it appropriately.
4. **isEmpty():** Checks if the stack is empty. Returns True if empty, False otherwise.
Example:
Sample Input: 1
4
push 10
push 20
peek
pop
Sample Output: 1
20
20
Sample Input: 2
3
push 5
pop
isEmpty
Sample Output: 2
5
True
Register No: 23105050
Sample Input: 3
3
push 15
peek
isEmpty
Sample Output: 3
15
False
Input Format:
The first line of input contains an integer 'n' indicating the number of operations. The following 'n'
lines contain operations in the format: 'operationName value' (for push) or 'operationName' (for other
operations).
Output Format:
The output should print the results of each 'peek', 'pop', 'isEmpty', and 'size' operation on separate
lines, as demonstrated in the sample input-output pairs.
Constraints:
The input will always be valid and follow the specified format. The number of operations (n) will be
within a reasonable range (1 <= n <= 1000).
Hint:
Use a Node class to represent elements in the linked list. Each node should store the data and a
reference to the next node. The stack can be represented by a head pointer, initially pointing to None.
Naming Conventions:
Use descriptive variable names like 'Node', 'data', 'next', 'head', 'push', 'pop', 'peek', etc.
Solution
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.top = None
self.top = new_node
def pop(self):
if self.isEmpty():
return "Stack is empty"
popped_value = self.top.data
self.top = self.top.next
return popped_value
def peek(self):
if self.isEmpty():
return "Stack is empty"
return self.top.data
def isEmpty(self):
return self.top is None
def size(self):
count = 0
current = self.top
while current:
count += 1
current = current.next
return count
def main():
stack = Stack()
n = int(input())
for _ in range(n):
operation = input().split()
if operation[0] == 'push':
stack.push(int(operation[1]))
elif operation[0] == 'pop':
print(stack.pop())
elif operation[0] == 'peek':
print(stack.peek())
elif operation[0] == 'isEmpty':
print(stack.isEmpty())
elif operation[0] == 'size':
print(stack.size())
if __name__ == "__main__":
main()
Analysis:
Implement a Queue abstract data type (ADT) in Python using a linked list as the underlying data
structure. Your implementation should include the following methods: 1. `enqueue(data)`: Adds an
element with `data` to the rear of the queue. 2. `dequeue()`: Removes and returns the element at the
front of the queue. Raises an exception if the queue is empty. 3. `front()`: Returns the element at the
front of the queue without removing it. Raises an exception if the queue is empty. 4. `is_empty()`:
Returns `True` if the queue is empty, `False` otherwise. 5. `size()`: Returns the number of elements in
the queue.
Example:
Sample Input: 1
4
enqueue 10
enqueue 20
dequeue
size
Sample Output: 1
10
1
Sample Input: 2
3
enqueue 5
enqueue 15
dequeue
Sample Output: 2
Sample Input: 3
3
enqueue 30
dequeue
size
Register No: 23105050
Sample Output: 3
30
0
Input Format:
The first line of input contains an integer 'n' representing the number of operations. The following 'n'
lines each contain an operation to be performed on the queue. Each operation is specified by a
keyword followed by optional arguments (e.g., 'enqueue 5').
Output Format:
For each 'dequeue' and 'front' operation, print the returned value on a new line. For each 'size'
operation, print the size of the queue on a new line.
Constraints:
The input will always be valid and follow the specified format. The maximum size of the queue is not
specified.
Hint:
Use a class to represent the queue and a separate class to represent the nodes in the linked list. Each
node should store the data and a reference to the next node.
Naming Conventions:
Use descriptive names like 'Queue' for the queue class, 'Node' for the node class, 'data' for the data
stored in a node, 'front' for the front of the queue, 'rear' for the rear of the queue, etc.
Solution
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Queue:
def __init__(self):
self.front = None
self.rear = None
self._size = 0
def dequeue(self):
if self.is_empty():
return "Queue is empty"
dequeued_value = self.front.data
self.front = self.front.next
if self.front is None:
self.rear = None
self._size -= 1
return dequeued_value
def front_value(self):
if self.is_empty():
return "Queue is empty"
return self.front.data
def is_empty(self):
return self.front is None
def size(self):
return self._size
def main():
queue = Queue()
n = int(input())
for _ in range(n):
operation = input().split()
if operation[0] == "enqueue":
queue.enqueue(int(operation[1]))
elif operation[0] == "dequeue":
print(queue.dequeue())
elif operation[0] == "front":
print(queue.front_value())
elif operation[0] == "is_empty":
print(queue.is_empty())
elif operation[0] == "size":
print(queue.size())
if __name__ == "__main__":
main()
Analysis:
Implement a Stack Abstract Data Type (ADT) in Python using a list as the underlying data structure.
Your implementation should handle a dynamic number of inputs, allowing the user to perform stack
operations like push, pop, peek, and check if the stack is empty.
Example:
Sample Input: 1
5
push 1
push 2
peek
pop
peek
Sample Output: 1
2
1
Sample Input: 2
7
push 10
push 20
push 30
pop
peek
push 40
peek
Sample Output: 2
20
40
Sample Input: 3
9
push 100
push 200
Register No: 23105050
push 300
pop
pop
peek
push 400
pop
peek
Sample Output: 3
100
100
Input Format:
The first line contains an integer 'n' representing the number of operations. The following 'n' lines each
contain an operation in the format: 'operation' or 'operation value', where 'operation' can be 'push',
'pop', 'peek', or 'isEmpty'.
Output Format:
For each 'peek' operation, print the top element of the stack on a new line. For 'pop' operations, output
nothing if the stack is empty.
Constraints:
The input will always be valid and follow the specified format. The number of inputs (operations) will
be a positive integer.
Hint:
Use a Python list to store stack elements. Implement methods for push (append to the list), pop
(remove from the end of the list), peek (access the last element), and check if the list is empty.
Naming Conventions:
Solution
class Stack:
def __init__(self):
self.stack=[]
def push(self,data):
Register No: 23105050
self.stack.append(data)
def pop(self):
if not self.is_empty():
return self.stack.pop()
def peek(self):
if not self.is_empty():
return self.stack[-1]
def is_empty(self):
return len(self.stack)==0
if __name__ == "__main__":
s=Stack()
n=int(input())
for i in range(n):
temp=input()
operation=temp.split()
if operation[0]=='push':
data=int(operation[1])
s.push(data)
elif operation[0]=='pop':
s.pop()
elif operation[0]=='peek':
print(s.peek())
elif operation[0]=='isEmpty':
print(s.is_empty())
Analysis:
Imagine you're designing a system to manage song requests in a music streaming app. Users can add
songs to a queue, and the system plays them in the order they were added. However, to avoid
extremely long wait times, you've decided to limit the queue's size. Your task is to implement this song
request queue using a circular queue data structure in Python. Since the number of song requests can
vary greatly, your implementation should dynamically adjust the queue's size as needed.
Example:
Sample Input: 1
5
ENQUEUE Faded
ENQUEUE Closer
ENQUEUE Let Her Go
DEQUEUE
ENQUEUE One Last Time
Sample Output: 1
Sample Input: 2
7
ENQUEUE Shape of You
ENQUEUE Despacito
ENQUEUE Believer
DEQUEUE
DEQUEUE
ENQUEUE Thunder
ENQUEUE Happy
Sample Output: 2
Sample Input: 3
4
ENQUEUE Song A
ENQUEUE Song B
DEQUEUE
DEQUEUE
Sample Output: 3
Input Format:
The first line of input indicates the number of operations. Subsequent lines each contain an operation:
'ENQUEUE ' to add a song or 'DEQUEUE' to remove a song.
Output Format:
For each operation, print a message indicating the result: 'Queue is Empty' if DEQUEUE is called on
an empty queue, ' added to the queue' after adding a song, or ' is removed from the queue' after
removing a song.
Constraints:
The maximum number of songs in the queue at any given time will not exceed 1000.
Hint:
Use a fixed-size list and manage its elements in a circular fashion using modulo operation for index
calculation. Use front and rear pointers to keep track of the start and end of the queue.
Naming Conventions:
Use descriptive variable names like 'queue', 'front', 'rear', 'size' etc.
Solution
class Node:
def __init__(self,data):
self.data=data
self.next=None
Register No: 23105050
def str(self):
return self.data
class Queue:
def __init__(self):
self.rear=None
self.front=None
def enqueue(self,data):
newnode=Node(data)
if self.rear is None:
self.rear=newnode
self.front=newnode
self.rear.next=self.front
else:
self.rear.next=newnode
self.rear=newnode
self.rear.next=self.front
print(f"{newnode.data} added to the queue")
def dequeue(self):
if self.front is None:
print("Queue is empty")
return
removed=self.front.data
if self.front==self.rear:
self.front=None
self.rear=None
else:
self.front=self.front.next
self.rear.next=self.front
obj=Queue()
n=int(input())
for i in range(n):
op=input().split()
oper=op[0]
if oper=='ENQUEUE':
st=' '.join(op[1:])
obj.enqueue(st)
elif oper=='DEQUEUE':
obj.dequeue()
Analysis:
Register No: 23105050
Your task is to implement a Singly Linked List in Python. A Singly Linked List is a linear data
structure where each element (node) points to the next element in the sequence. The last element's next
pointer points to null, indicating the end of the list. Your implementation should include the following
operations:
1. Insertion:
Insert at the beginning of the list
Insert at the end of the list
Insert after a given node
2. Deletion:
Delete the head node
Delete the tail node
Delete a node with a given value
3. Traversal:
Print all the elements of the linked list
Example:
Sample Input: 1
8
1 10
1 20
2 30
3 25 20
4
6 30
5
4
Sample Output: 1
20 25 10 30
20 25
Sample Input: 2
10
1 15
1 10
2 20
2 25
3 20 30
Register No: 23105050
4
5
4
6 10
4
Sample Output: 2
10 15 20 25
10 15 20
15 20
Sample Input: 3
6
15
2 10
4
5
4
65
Sample Output: 3
5 10
5
Input Format:
1. The first line contains an integer n (number of operations).
2. The next n lines contain the following operations:
1 x: Insert x at the beginning.
2 x: Insert x at the end.
3 x y: Insert x after the node with value y.
4: Print the current linked list.
5: Delete the tail node.
6 x: Delete the node with value x.
Output Format:
For every 4 operation, print the linked list elements in one line, separated by a space. If the list is
empty, print "The list is empty."
Constraints:
1. The number of operations (insertions, deletions, printing) will be within the range [1, 1000]. 2. The
values to be inserted will be integers within the range [-1000, 1000].
Hint:
Register No: 23105050
Use a class to represent the Node of the linked list, containing data and a reference to the next node.
Another class can represent the LinkedList itself, containing the head of the list and methods for
various operations.
Naming Conventions:
Use CamelCase for class names (e.g., `LinkedList`, `Node`) and lowercase with underscores for
variable and function names (e.g., `head_node`, `insert_at_end`).
Solution
class Node:
def __init__(self,data):
self.data=data
self.next=None
class Sll:
def __init__(self):
self.head=None
self.temp=None
def creation(self,data):
newnode=Node(data)
if self.head is None:
self.head=newnode
self.temp=newnode
else:
self.temp.next=newnode
self.temp=newnode
def insert_at_beginning(self,data):
newnode=Node(data)
newnode.next=self.head
self.head=newnode
def insert_at_end(self,data):
newnode=Node(data)
self.temp=self.head
while(self.temp.next!=None):
self.temp=self.temp.next
self.temp.next=newnode
def insert_after(self,data,value):
if(self.head.data==value):
newnode=Node(data)
newnode.next=self.head.next
self.head.next=newnode
else:
flag=0
self.temp=self.head
while(self.temp.data!=value):
prev=self.temp
self.temp=self.temp.next
if self.temp.data!=value:
return
else:
Register No: 23105050
flag=1
if flag==1:
newnode=Node(data)
newnode.next=self.temp.next
self.temp.next=newnode
def delete_tail(self):
self.temp=self.head
while(self.temp.next!=None):
prev=self.temp
self.temp=self.temp.next
prev.next=None
del(self.temp)
def delete_node(self,value):
if(self.head.data==value):
self.temp=self.head
self.head=self.head.next
self.temp.next=None
del(self.temp)
else:
self.temp=self.head
while(self.temp.data!=value):
prev =self.temp
self.temp=self.temp.next
prev.next=self.temp.next
del(self.temp)
def display(self):
self.temp=self.head
while(self.temp):
print(self.temp.data,end=" ")
self.temp=self.temp.next
print()
if __name__== "__main__":
s=Sll()
n=int(input())
for i in range(n):
operation=input()
temp=operation.split()
num1=int(temp[0])
if num1==1:
data=int(temp[1])
s.insert_at_beginning(data)
elif num1==2:
data=int(temp[1])
s.insert_at_end(data)
elif num1==3:
data=int(temp[1])
value=int(temp[2])
s.insert_after(data,value)
elif num1==5:
s.delete_tail()
elif num1==6:
num2=int(temp[1])
Register No: 23105050
s.delete_node(num2)
elif num1==4:
s.display()
Analysis:
Create a Python program that implements the infix-to-postfix conversion algorithm using a linked list
for the postfix expression and a stack data structure. The program should accept dynamic input,
allowing the user to enter infix expressions of varying lengths and complexities.
Example:
Sample Input: 1
a+b*c-d/e
Sample Output: 1
abc*+de/-
Sample Input: 2
(a+b)*(c-d)/e
Sample Output: 2
ab+cd-*e/
Sample Input: 3
a+b*(c^d-e)^(f+g*h)-i
Sample Output: 3
abcd^e-fgh*+^+i-
Input Format:
The input will be a single line string representing the infix expression.
Output Format:
The output will be a single line string representing the postfix expression.
Register No: 23105050
Constraints:
The input infix expressions will contain only single-letter variables, operators (+, -, *, /, ^), and
parentheses ((, )).
Hint:
Use a stack to store operators and parentheses. Process the infix expression character by character,
appending operands directly to the postfix expression and handling operators based on precedence.
Naming Conventions:
Follow standard Python naming conventions: use lowercase with underscores for variable and
function names (e.g., `infix_expression`, `push_to_stack`).
Solution
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Stack:
def __init__(self):
self.top = None
def is_empty(self):
return self.top is None
def pop(self):
if self.is_empty():
return None
popped_data = self.top.data
self.top = self.top.next
return popped_data
def peek(self):
if self.is_empty():
return None
return self.top.data
def is_operand(ch):
return ch.isalnum()
def precedence(op):
if op in ('+', '-'):
return 1
if op in ('*', '/'):
return 2
if op == '^':
return 3
return -1
Register No: 23105050
def infix_to_postfix(expression):
stack = Stack()
result = []
for ch in expression:
if is_operand(ch):
result.append(ch)
elif ch == '(':
stack.push(ch)
elif ch == ')':
while not stack.is_empty() and stack.peek() != '(':
result.append(stack.pop())
stack.pop() # pop '(' from the stack
else:
while (not stack.is_empty() and
precedence(ch) <= precedence(stack.peek())):
result.append(stack.pop())
stack.push(ch)
return ''.join(result)
def main():
expression = input()
print(infix_to_postfix(expression))
if __name__ == "__main__":
main()
Analysis:
You need to implement a Stack Abstract Data Type (ADT) using a Linked List in Python. Your
program should handle a dynamic number of inputs. The Stack ADT should support the following
operations:
2. **Pop ():** Removes and returns the element at the top of the stack. If the stack is empty, it should
indicate an error (e.g., return a specific message or raise an exception).
3. **Peek():** Returns the element at the top of the stack without removing it. If the stack is empty,
handle it appropriately.
4. **isEmpty():** Checks if the stack is empty. Returns True if empty, False otherwise.
Example:
Sample Input: 1
4
push 10
push 20
peek
pop
Sample Output: 1
20
20
Sample Input: 2
3
push 5
pop
isEmpty
Sample Output: 2
5
True
Register No: 23105050
Sample Input: 3
3
push 15
peek
isEmpty
Sample Output: 3
15
False
Input Format:
The first line of input contains an integer 'n' indicating the number of operations. The following 'n'
lines contain operations in the format: 'operationName value' (for push) or 'operationName' (for other
operations).
Output Format:
The output should print the results of each 'peek', 'pop', 'isEmpty', and 'size' operation on separate
lines, as demonstrated in the sample input-output pairs.
Constraints:
The input will always be valid and follow the specified format. The number of operations (n) will be
within a reasonable range (1 <= n <= 1000).
Hint:
Use a Node class to represent elements in the linked list. Each node should store the data and a
reference to the next node. The stack can be represented by a head pointer, initially pointing to None.
Naming Conventions:
Use descriptive variable names like 'Node', 'data', 'next', 'head', 'push', 'pop', 'peek', etc.
Solution
class Node:
def __init__(self,data):
self.data=data
self.next=None
class Stack:
def __init__(self):
self.top=None
def push(self,x):
newnode=Node(x)
newnode.next=self.top
self.top=newnode
def pop(self):
Register No: 23105050
if self.isEmpty():
return " Stack is empty"
popped_value=self.top.data
self.top=self.top.next
return popped_value
def peek(self):
if self.isEmpty():
return "Stack is empty"
return self.top.data
def isEmpty(self):
return self.top is None
def size(self):
count=0
current=self.top
while current:
count+=1
current=current.next
return count
def main():
stack = Stack()
n=int(input())
for _ in range(n):
operation=input().split()
if operation[0]=='push':
stack.push(int(operation[1]))
elif operation[0]=='pop':
print(stack.pop())
elif operation[0]== 'peek':
print(stack.peek())
elif operation[0]=='isEmpty':
print(stack.isEmpty())
elif operation[0]=='size':
print(stack.size())
if __name__ == "__main__":
main()
Analysis: