Lab Questions soluations with output 1-5
Lab Questions soluations with output 1-5
1. Write a program to implement stack using arrays and evaluate a given postfix expression
class Stack:
def __init__(self):
self.stack = []
def is_empty(self):
return len(self.stack) == 0
def pop(self):
if not self.is_empty():
return self.stack.pop()
else:
raise IndexError("Stack is empty")
def peek(self):
if not self.is_empty():
return self.stack[-1]
else:
raise IndexError("Stack is empty")
def evaluate_postfix(expression):
stack = Stack()
for char in expression:
if char.isdigit(): # If the character is an operand, push it onto the stack
stack.push(int(char))
else:
# Pop two operands for the operator
right_operand = stack.pop()
left_operand = stack.pop()
if char == '+':
stack.push(left_operand + right_operand)
elif char == '-':
stack.push(left_operand - right_operand)
elif char == '*':
stack.push(left_operand * right_operand)
elif char == '/':
stack.push(left_operand / right_operand)
else:
raise ValueError(f"Unknown operator: {char}")
return stack.pop()
# Example Usage
if __name__ == "__main__":
postfix_expression = "231*+9-" # Example postfix expression
print(f"Postfix Expression: {postfix_expression}")
result = evaluate_postfix(postfix_expression)
print(f"Result: {result}")
Output
For the given postfix expression 231*+9-, the program will output:
mathematica
CopyEdit
Postfix Expression: 231*+9-
Result: -4
Explanation
1. Parse 2, 3, and 1 as operands.
2. Compute 3 * 1 = 3 and push the result back.
3. Add 2 + 3 = 5 and push the result back.
4. Subtract 5-9=-4.
2. Write a program to implement circular queue using arrays
class CircularQueue:
def __init__(self, size):
self.size = size
self.queue = [None] * size
self.front = -1
self.rear = -1
def is_full(self):
return (self.rear + 1) % self.size == self.front
def is_empty(self):
return self.front == -1
def dequeue(self):
if self.is_empty():
print("Queue is empty! Cannot dequeue.")
return None
item = self.queue[self.front]
if self.front == self.rear: # Queue becomes empty after this operation
self.front = self.rear = -1
else:
self.front = (self.front + 1) % self.size
print(f"Dequeued: {item}")
return item
def display(self):
if self.is_empty():
print("Queue is empty!")
return
print("Circular Queue elements:")
i = self.front
while True:
print(self.queue[i], end=" ")
if i == self.rear:
break
i = (i + 1) % self.size
print()
# Example Usage
if __name__ == "__main__":
cq = CircularQueue(5) # Circular Queue of size 5
cq.enqueue(10)
cq.enqueue(20)
cq.enqueue(30)
cq.enqueue(40)
cq.enqueue(50)
cq.display()
cq.dequeue()
cq.dequeue()
cq.display()
cq.enqueue(60)
cq.enqueue(70)
cq.display()
Output
For the above example, the output will be:
yaml
CopyEdit
Enqueued: 10
Enqueued: 20
Enqueued: 30
Enqueued: 40
Enqueued: 50
Circular Queue elements:
10 20 30 40 50
Dequeued: 10
Dequeued: 20
Circular Queue elements:
30 40 50
Enqueued: 60
Enqueued: 70
Circular Queue elements:
30 40 50 60 70
Explanation
1. The queue is initialized with size 5.
2. Elements 10, 20, 30, 40, 50 are enqueued.
3. Two elements (10 and 20) are dequeued.
4. After dequeuing, two more elements (60 and 70) are enqueued to demonstrate the circular nature of the
queue.
def is_full(self):
return (self.rear + 1) % self.size == self.front
def is_empty(self):
return self.front == -1
def delete_front(self):
if self.is_empty():
print("Deque is empty! Cannot delete from front.")
return None
item = self.deque[self.front]
if self.front == self.rear: # Deque becomes empty after this operation
self.front = self.rear = -1
else:
self.front = (self.front + 1) % self.size
print(f"Deleted {item} from the front.")
return item
def delete_rear(self):
if self.is_empty():
print("Deque is empty! Cannot delete from rear.")
return None
item = self.deque[self.rear]
if self.front == self.rear: # Deque becomes empty after this operation
self.front = self.rear = -1
else:
self.rear = (self.rear - 1 + self.size) % self.size
print(f"Deleted {item} from the rear.")
return item
def display(self):
if self.is_empty():
print("Deque is empty!")
return
print("Deque elements:")
i = self.front
while True:
print(self.deque[i], end=" ")
if i == self.rear:
break
i = (i + 1) % self.size
print()
# Example Usage
if __name__ == "__main__":
dq = Deque(5) # Deque of size 5
dq.insert_rear(10)
dq.insert_rear(20)
dq.insert_front(5)
dq.insert_front(2)
dq.display()
dq.delete_rear()
dq.delete_front()
dq.display()
dq.insert_rear(30)
dq.insert_front(1)
dq.display()
Output
For the above example, the output will be:
yaml
CopyEdit
Inserted 10 at the rear.
Inserted 20 at the rear.
Inserted 5 at the front.
Inserted 2 at the front.
Deque elements:
2 5 10 20
Deleted 20 from the rear.
Deleted 2 from the front.
Deque elements:
5 10
Inserted 30 at the rear.
Inserted 1 at the front.
Deque elements:
1 5 10 30
Explanation
1. Insert operations are performed at both the front and rear of the deque.
2. Delete operations remove elements from the respective ends.
3. Circular indexing ensures efficient use of the array, and the program handles both overflow and
underflow conditions effectively.
def pop(self):
if not self.is_empty():
return self.stack.pop()
return None
def peek(self):
if not self.is_empty():
return self.stack[-1]
return None
def is_empty(self):
return len(self.stack) == 0
def is_balanced(expression):
stack = Stack()
pairs = {')': '(', ']': '[', '}': '{'}
Output:
Expression: {[()()]} -> Balanced: True
Expression: {[(])} -> Balanced: False
class SingleLinkedList:
def __init__(self):
self.head = None
if self.head.data == value:
self.head = self.head.next
print(f"Deleted {value} from the list.")
return
current = self.head
while current.next and current.next.data != value:
current = current.next
if current.next:
current.next = current.next.next
print(f"Deleted {value} from the list.")
else:
print(f"{value} not found in the list.")
def display(self):
if self.head is None:
print("List is empty.")
return
print("Single Linked List: ", end="")
current = self.head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")
# Example Usage
if __name__ == "__main__":
sll = SingleLinkedList()
sll.insert_at_end(10)
sll.insert_at_end(20)
sll.insert_at_end(30)
sll.display()
sll.delete_by_value(20)
sll.display()
Output:
rust
CopyEdit
Inserted 10 at the end.
Inserted 20 at the end.
Inserted 30 at the end.
Single Linked List: 10 -> 20 -> 30 -> None
Deleted 20 from the list.
Single Linked List: 10 -> 30 -> None
class DoubleLinkedList:
def __init__(self):
self.head = None
current = self.head
while current and current.data != value:
current = current.next
if current is None:
print(f"{value} not found in the list.")
return
if current.prev:
current.prev.next = current.next
if current.next:
current.next.prev = current.prev
def display_forward(self):
if self.head is None:
print("List is empty.")
return
print("Double Linked List (Forward): ", end="")
current = self.head
while current:
print(current.data, end=" <-> ")
current = current.next
print("None")
def display_backward(self):
if self.head is None:
print("List is empty.")
return
print("Double Linked List (Backward): ", end="")
current = self.head
while current.next:
current = current.next
while current:
print(current.data, end=" <-> ")
current = current.prev
print("None")
# Example Usage
if __name__ == "__main__":
dll = DoubleLinkedList()
dll.insert_at_end(10)
dll.insert_at_end(20)
dll.insert_at_end(30)
dll.display_forward()
dll.display_backward()
dll.delete_by_value(20)
dll.display_forward()
dll.display_backward()
Output:
rust
CopyEdit
Inserted 10 at the end.
Inserted 20 at the end.
Inserted 30 at the end.
Double Linked List (Forward): 10 <-> 20 <-> 30 <-> None
Double Linked List (Backward): 30 <-> 20 <-> 10 <-> None
Deleted 20 from the list.
Double Linked List (Forward): 10 <-> 30 <-> None
Double Linked List (Backward): 30 <-> 10 <-> None
Applications:
1. Single Linked List:
o Dynamic memory allocation.
o Used in scheduling, like CPU task management.
2. Double Linked List:
o Navigation in both directions (e.g., browser history, undo-redo functionality).
o Used in managing memory blocks in OS.
These programs show how to implement and apply both single and double linked lists.
(b) Double Linked List Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None
class DoubleLinkedList:
def __init__(self):
self.head = None
if current is None:
print(f"{value} not found in the list.")
return
if current.prev:
current.prev.next = current.next
if current.next:
current.next.prev = current.prev
def display_forward(self):
if self.head is None:
print("List is empty.")
return
print("Double Linked List (Forward): ", end="")
current = self.head
while current:
print(current.data, end=" <-> ")
current = current.next
print("None")
def display_backward(self):
if self.head is None:
print("List is empty.")
return
print("Double Linked List (Backward): ", end="")
current = self.head
while current.next:
current = current.next
while current:
print(current.data, end=" <-> ")
current = current.prev
print("None")
# Example Usage
if __name__ == "__main__":
dll = DoubleLinkedList()
dll.insert_at_end(10)
dll.insert_at_end(20)
dll.insert_at_end(30)
dll.display_forward()
dll.display_backward()
dll.delete_by_value(20)
dll.display_forward()
dll.display_backward()
Output:
Inserted 10 at the end.
Inserted 20 at the end.
Inserted 30 at the end.
Double Linked List (Forward): 10 <-> 20 <-> 30 <-> None
Double Linked List (Backward): 30 <-> 20 <-> 10 <-> None
Deleted 20 from the list.
Double Linked List (Forward): 10 <-> 30 <-> None
Double Linked List (Backward): 30 <-> 10 <-> None
Applications:
1. Single Linked List:
o Dynamic memory allocation.
o Used in scheduling, like CPU task management.
2. Double Linked List:
o Navigation in both directions (e.g., browser history, undo-redo functionality).
o Used in managing memory blocks in OS.