0% found this document useful (0 votes)
16 views12 pages

Lab Questions soluations with output 1-5

The document provides implementations for various data structures including stacks, circular queues, double-ended queues, single linked lists, and double linked lists, along with their applications. Each data structure is accompanied by example code and explanations of operations such as insertion, deletion, and evaluation of expressions. Additionally, it includes practical applications like balanced parentheses checking and memory management in operating systems.

Uploaded by

skymishra81
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views12 pages

Lab Questions soluations with output 1-5

The document provides implementations for various data structures including stacks, circular queues, double-ended queues, single linked lists, and double linked lists, along with their applications. Each data structure is accompanied by example code and explanations of operations such as insertion, deletion, and evaluation of expressions. Additionally, it includes practical applications like balanced parentheses checking and memory management in operating systems.

Uploaded by

skymishra81
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 12

LAB Experiments

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 push(self, item):


self.stack.append(item)

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 enqueue(self, item):


if self.is_full():
print("Queue is full! Cannot enqueue.")
return
if self.front == -1: # First element to enqueue
self.front = 0
self.rear = (self.rear + 1) % self.size
self.queue[self.rear] = item
print(f"Enqueued: {item}")

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.

3. Write a program to implement double ended queue (de queue) using


arrays
class Deque:
def __init__(self, size):
self.size = size
self.deque = [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 insert_front(self, item):


if self.is_full():
print("Deque is full! Cannot insert at front.")
return
if self.is_empty(): # First element to insert
self.front = self.rear = 0
else:
self.front = (self.front - 1 + self.size) % self.size
self.deque[self.front] = item
print(f"Inserted {item} at the front.")

def insert_rear(self, item):


if self.is_full():
print("Deque is full! Cannot insert at rear.")
return
if self.is_empty(): # First element to insert
self.front = self.rear = 0
else:
self.rear = (self.rear + 1) % self.size
self.deque[self.rear] = item
print(f"Inserted {item} at the rear.")

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.

4. Write programs for applications based on stacks and queues.


Application 1: Balanced Parentheses (Stack)
class Stack:
def __init__(self):
self.stack = []

def push(self, item):


self.stack.append(item)

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 = {')': '(', ']': '[', '}': '{'}

for char in expression:


if char in '([{':
stack.push(char)
elif char in ')]}':
if stack.is_empty() or stack.pop() != pairs[char]:
return False
return stack.is_empty()
# Example Usage
if __name__ == "__main__":
expr1 = "{[()()]}"
expr2 = "{[(])}"

print(f"Expression: {expr1} -> Balanced: {is_balanced(expr1)}")


print(f"Expression: {expr2} -> Balanced: {is_balanced(expr2)}")

Output:
Expression: {[()()]} -> Balanced: True
Expression: {[(])} -> Balanced: False

5. Write programs to implement the following data structures and their


applications
(a) Single linked list
(b) Double linked list
(a) Single Linked List Implementation
class Node:
def __init__(self, data):
self.data = data
self.next = None

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

def insert_at_end(self, data):


new_node = Node(data)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
print(f"Inserted {data} at the end.")

def delete_by_value(self, value):


if self.head is None:
print("List is empty. Nothing to delete.")
return

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

(b) Double Linked List Implementation


A double linked list has nodes with pointers to both the previous and next nodes.
Program:
python
CopyEdit
class Node:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None

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

def insert_at_end(self, data):


new_node = Node(data)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
new_node.prev = current
print(f"Inserted {data} at the end.")

def delete_by_value(self, value):


if self.head is None:
print("List is empty. Nothing to delete.")
return

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

if current == self.head: # If head node is being deleted


self.head = current.next

print(f"Deleted {value} from the list.")

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

def insert_at_end(self, data):


new_node = Node(data)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
new_node.prev = current
print(f"Inserted {data} at the end.")

def delete_by_value(self, value):


if self.head is None:
print("List is empty. Nothing to delete.")
return
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

if current == self.head: # If head node is being deleted


self.head = current.next

print(f"Deleted {value} from the list.")

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.

You might also like