0% found this document useful (0 votes)
28 views100 pages

6.DS Student LAB MANUAL (Updated)

data science and python

Uploaded by

Hitech Computer
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)
28 views100 pages

6.DS Student LAB MANUAL (Updated)

data science and python

Uploaded by

Hitech Computer
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/ 100

Ex: 1 Implement Simple ADT as class Stack ADT

Date:

Aim:
To Implement simple ADTs as Python classes using Stack, Queue, List using python.

Algorithm:
1. Create a Stack[ ], Queue[], List[] with MAX size as your wish.
2. Write function for all the basic operations of stack, Queue, List - PUSH(), POP() and
DISPLAY(), append(), Extend().
3. Close the program

Python Program :
Stack:
stack = []

# Push elements onto the stack


stack.append('a')
stack.append('b')
stack.append('c')

# Display the initial stack

print('Initial stack:')
print(stack)

# Pop elements from the stack


print('\nElements popped from stack:')
print(stack.pop())
print(stack.pop())
print(stack.pop())

# Display the stack after popping elements


print('\nStack after elements are popped:')
print(stack)

Queue:
queue = []

# Enqueue elements
queue.append('a')

1
queue.append('b')
queue.append('c')

# Display the initial queue


print("Initial queue:")
print(queue)

# Dequeue elements from the queue


print("\nElements dequeued from queue:")
print(queue.pop(0))
print(queue.pop(0))
print(queue.pop(0))

# Display the queue after removing elements


print("\nQueue after removing elements:")
int(queue)

List = [1, 2, 3, 4]

# Display the initial list


print("Initial List:")
print(List)

# Extend the list with new elements


List.extend([8, 'Geeks', 'Always'])

# Display the list after extend operation


print("\nList after performing Extend Operation:")
print(List)

Output:

2
Result:

Thus the Implementation of simple ADTs as Python classes was executed successfully.

3
Ex .no.02 Implement Recursive algorithms in Python.
Date :

Aim :
To implement recursive algorithms in Python for solving basic problems such as:
1. Calculating the factorial of a number
2. Generating the Fibonacci series
3. Finding the sum of natural numbers
4. Reversing a string
Algorithm :
Fibonacci
Step 1: If n is 0 or less, return 0
Step 2: If n is 1, return 1 (base case)
Step 3: Otherwise, return fibonacci(n-1) + fibonacci(n-2)

Sum of n natural numbers


Step 1: If n is 0, return 0 (base case)
Step 2: Otherwise, return n plus sum of natural numbers up to (n - 1)

Reverse a string
Step 1: If string is empty, return the empty string (base case)
Step 2: Otherwise, call reverse_string on substring from index 1,
then add first character (s[0]) to the end of the result

Loop until user selects Exit:


1. Ask for choice
2. If choice is 1 → input number → call factorial → display result
3. If choice is 2 → input number → call fibonacci() for each term → print series
4. If choice is 3 → input number → call sum_natural → display result
5. If choice is 4 → input string → call reverse_string → display result
6. If choice is 5 → Exit loop
7. Else → show invalid input

Python program
def factorial(n):
if n == 0 or n == 1:
return 1
return n * factorial(n - 1)

def fibonacci(n):
4
if n <= 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n - 2)

def sum_natural(n):
if n == 0:
return 0
return n + sum_natural(n - 1)

def reverse_string(s):
if len(s) == 0:
return s
return reverse_string(s[1:]) + s[0]

# Main menu program


if name == " main ":
while True:
print("\n--- Recursive Algorithms Menu ---")
print("1. Factorial")
print("2. Fibonacci")
print("3. Sum of Natural Numbers")
print("4. Reverse String")
print("5. Exit")
choice = input("Enter your choice (1-5): ")

if choice == '1':
n = int(input("Enter a number to calculate factorial: "))
print(f"Factorial of {n} is {factorial(n)}")

elif choice == '2':


n = int(input("Enter the number of terms for Fibonacci series: "))
print("Fibonacci series: ", end='')
for i in range(n):
print(fibonacci(i), end=' ')
print()

elif choice == '3':


n = int(input("Enter a number to calculate sum of natural numbers: "))
5
print(f"Sum of first {n} natural numbers is {sum_natural(n)}")

elif choice == '4':


s = input("Enter a string to reverse: ")
print(f"Reversed string is: {reverse_string(s)}")

elif choice == '5':


print("Exiting program...")
break

else:
print("Invalid choice! Please enter 1-5.")

Output

Result:
Thus, the Python program for performing recursive operations (Factorial, Fibonacci,
Sum of Natural Numbers, and String Reversal) was executed successfully and the outputs
were verified.
6
Ex .no.03 Implement List ADT using Python Arrays
Date :

Aim:
To implement List Abstract Data Type (List ADT) using a fixed-size array in
Python, with basic operations such as insert, delete, search, update, and traverse.

Algorithm:
1. Initialization:
Step : 1Create a list with fixed capacity.
Step 2: Initialize size = 0.
2. Insert(index, value):
Step 1: Check if the list is full.
Step 2: Check if the index is within bounds.
Step 3: Shift elements right from the given index.
Step 4: Insert the value and increment size.
3. Delete(index):
Step 1: Check if the list is empty.
Step 2: Validate index.
Step 3: Shift elements left to overwrite the deleted value.
Step 4: Decrease the size.
4. Search(value):
Step 1: Traverse the list from index 0 to size - 1.
Step 2: If value is found, return index; otherwise return -1.
5. Update(index, value):
Step 1: Validate index.
Step 2: Replace old value at given index with new value.
6. Traverse():
Step 1: Print all elements from index 0 to size - 1.

Python program
class ListADT:
def init (self, capacity):
self.data = [None] * capacity # Simulate array with fixed capacity
self.size = 0
self.capacity = capacity

def is_full(self):
return self.size == self.capacity

7
def is_empty(self):
return self.size == 0

def insert(self, index, value):


if self.is_full():
print("List is full!")
return

if index < 0 or index > self.size:


print("Invalid index!")
return

for i in range(self.size, index, -1):


self.data[i] = self.data[i-1]

self.data[index] = value
self.size += 1
print(f"Inserted {value} at position {index}.")

def delete(self, index):


if self.is_empty():
print("List is empty!")
return

if index < 0 or index >= self.size:


print("Invalid index!")
return

print(f"Deleted {self.data[index]} from position {index}.")


for i in range(index, self.size - 1):
self.data[i] = self.data[i+1]

self.data[self.size - 1] = None
self.size -= 1

def search(self, value):


for i in range(self.size):
if self.data[i] == value:
return i
return -1
8
def update(self, index, value):
if index < 0 or index >= self.size:
print("Invalid index!")
return
old_value = self.data[index]
self.data[index] = value
print(f"Updated position {index}: {old_value} -> {value}")

def traverse(self):
if self.is_empty():
print("List is empty!")
else:
print("List elements:", end=' ')
for i in range(self.size):
print(self.data[i], end=' ')
print()

# Main program with runtime input


if name == " main ":
capacity = int(input("Enter capacity of list: "))
lst = ListADT(capacity)

while True:
print("\n--- List ADT Menu ---")
print("1. Insert")
print("2. Delete")
print("3. Search")
print("4. Update")
print("5. Traverse")
print("6. Exit")

choice = input("Enter your choice (1-6): ")

if choice == '1':
value = input("Enter value to insert: ")
index = int(input("Enter position to insert (0-based index): "))
lst.insert(index, value)

elif choice == '2':


9
index = int(input("Enter index to delete: "))
lst.delete(index)

elif choice == '3':


value = input("Enter value to search: ")
index = lst.search(value)
if index != -1:
print(f"Element found at index {index}")
else:
print("Element not found!")

elif choice == '4':


index = int(input("Enter index to update: "))
value = input("Enter new value: ")
lst.update(index, value)

elif choice == '5':


lst.traverse()

elif choice == '6':


print("Exiting program...")
break

else:
print("Invalid choice! Please select between 1-6.")

Output

10
Result:
Thus, the above Python program was executed successfully for implementing List
ADT using a fixed-size array and the outputs were verified

11
Ex.no.04a Implementations of List using SLL
Date :

Aim:
To implement basic operations on a Singly Linked List (SLL) in Python, such as
insertion (beginning, end, specific position), deletion, search, and traversal (display).

Algorithm:
1. Insert at Beginning
Step 1: Create a new node.
Step 2: Set new_node.next = head
Step 3: Update head = new_node
2. Insert at End
Step 1: Create a new node.
Step 2: If list is empty, set head = new_node
Step 3: Else, traverse to the last node and set last.next = new_node
3. Insert at Specific Position
Step 1: If position = 0, call insert_at_beginning.
Step 2: Else, traverse the list to (position - 1)
Step 3: Insert new node after that position.
4. Delete at Beginning
Step 1: If list is empty, print message.
Step 2: Else, set head = head.next
5. Delete at End
Step 1: If list is empty or only one node, update head = None
Step 2: Else, traverse to second-last node and set node.next = None
6. Delete at Specific Position
Step 1: If position = 0, delete head
Step 2: Else, traverse to (position - 1)
Step 3: Set current.next = current.next.next
7. Search
Step 1: Traverse from head to end
Step 2: Compare each node‘s data with the key
Step 3: If found, return position; else return -1
8. Display
Step 1: Traverse from head to end
Step 2: Print each node's data followed by -> until None

12
Python program
class Node:
def init (self, data):
self.data = data
self.next = None

class SinglyLinkedList:
def init (self):
self.head = None

def insert_at_beginning(self, data):


new_node = Node(data)
new_node.next = self.head
self.head = new_node

def insert_at_end(self, data):


new_node = Node(data)
if self.head is None:
self.head = new_node
return
temp = self.head
while temp.next:
temp = temp.next
temp.next = new_node

def insert_at_position(self, pos, data):


if pos == 0:
self.insert_at_beginning(data)
return
new_node = Node(data)
temp = self.head
count = 0
while temp and count < pos - 1:
temp = temp.next
count += 1
if temp is None:
print("Position out of range.")
return
new_node.next = temp.next
temp.next = new_node

13
def delete_at_beginning(self):
if self.head is None:
print("List is empty.")
else:
self.head = self.head.next

def delete_at_end(self):
if self.head is None:
print("List is empty.")
elif self.head.next is None:
self.head = None
else:
temp = self.head
while temp.next.next:
temp = temp.next
temp.next = None

def delete_at_position(self, pos):


if self.head is None:
print("List is empty.")
return
if pos == 0:
self.head = self.head.next
return
temp = self.head
count = 0
while temp.next and count < pos - 1:
temp = temp.next
count += 1
if temp.next is None:
print("Position out of range.")
else:
temp.next = temp.next.next

def search(self, key):


temp = self.head
pos = 0
while temp:
if temp.data == key:
return pos
14
temp = temp.next
pos += 1
return -1

def display(self):
temp = self.head
if not temp:
print("List is empty.")
return
while temp:
print(temp.data, end=" -> ")
temp = temp.next
print("None")
if name == " main ":
sll = SinglyLinkedList()

while True:
print("\n--- Singly Linked List Menu ---")
print("1. Insert at beginning")
print("2. Insert at end")
print("3. Insert at position")
print("4. Delete at beginning")
print("5. Delete at end")
print("6. Delete at position")
print("7. Search")
print("8. Display")
print("9. Exit")

choice = int(input("Enter your choice: "))

if choice == 1:
val = int(input("Enter value: "))
sll.insert_at_beginning(val)
sll.display()
elif choice == 2:
val = int(input("Enter value: "))
sll.insert_at_end(val)
sll.display()
elif choice == 3:
pos = int(input("Enter position: "))
15
val = int(input("Enter value: "))
sll.insert_at_position(pos, val)
sll.display()
elif choice == 4:
sll.delete_at_beginning()
sll.display()
elif choice == 5:
sll.delete_at_end()
sll.display()
elif choice == 6:
pos = int(input("Enter position: "))
sll.delete_at_position(pos)
sll.display()
elif choice == 7:
key = int(input("Enter value to search: "))
result = sll.search(key)
if result != -1:
print(f"Element found at position {result}")
else:
print("Element not found.")
elif choice == 8:
sll.display()
elif choice == 9:
print("Exiting...")
break
else:
print("Invalid choice. Try again.")

Output

16
Result:
Thus, the Python program to perform various operations on a Singly Linked List
was executed successfully and all the operations such as insertion, deletion, search, and
traversal were verified.
17
Ex.no.04b Implementations of List using DLL
Date :

Aim:
To implement a Doubly Linked List (DLL) in Python to perform the following
operations:
• Insertion (at beginning, end, and any given position)
• Deletion (at beginning, end, and any given position)
• Searching for an element
• Forward and backward traversal of the list

Algorithm:
1. Insert at Beginning
Step 1: Create a new node.
Step 2: Set new_node.next = head
Step 3: If head is not None, set head.prev = new_node
Step 4: Update head = new_node
2. Insert at End
Step 1: Create a new node.
Step 2: If list is empty, set head = new_node
Step 3: Else, traverse to the last node
Step 4: Set last_node.next = new_node and new_node.prev = last_node
3. Insert at Given Position
Step 1: If pos = 0, call insert_at_beginning
Step 2: Traverse to the (pos - 1)th node
Step 3: Update pointers:
- new_node.next = current.next
- new_node.prev = current
- If current.next exists, current.next.prev = new_node
- current.next = new_node
4. Delete at Beginning
Step 1: If list is empty, print message
Step 2: Move head to head.next
Step 3: If head is not None, set head.prev = None
5. Delete at End
Step 1: If list is empty or has one node, set head = None
Step 2: Else, traverse to last node
Step 3: Set second_last.next = None
6. Delete at Given Position
Step 1: If pos = 0, call delete_at_beginning
18
Step 2: Traverse to the node at position pos
Step 3: Update links:
- temp.prev.next = temp.next
- If temp.next exists, temp.next.prev = temp.prev
7. Search for an Element
Step 1: Traverse the list from head
Step 2: Compare each node‘s data with key
Step 3: If found, return index; else return -1
8. Display Forward
Step 1: Start from head and print data till the end

9. Display Backward
Step 1: Traverse to the last node
Step 2: Move backwards using prev pointers and print data

Python program
class Node:
def init (self, data):
self.data = data
self.prev = None
self.next = None

class DoublyLinkedList:
def init (self):
self.head = None

def insert_at_beginning(self, data):


new_node = Node(data)
new_node.next = self.head
if self.head:
self.head.prev = new_node
self.head = new_node

def insert_at_end(self, data):


new_node = Node(data)
if not self.head:
self.head = new_node
return
temp = self.head
while temp.next:
19
temp = temp.next
temp.next = new_node
new_node.prev = temp

def insert_at_position(self, pos, data):


if pos == 0:
self.insert_at_beginning(data)
return
new_node = Node(data)
temp = self.head
index = 0
while temp and index < pos - 1:
temp = temp.next
index += 1
if temp is None:
print("Position out of range.")
return
new_node.next = temp.next
new_node.prev = temp
if temp.next:
temp.next.prev = new_node
temp.next = new_node

def delete_at_beginning(self):
if not self.head:
print("List is empty.")
return
self.head = self.head.next
if self.head:
self.head.prev = None

def delete_at_end(self):
if not self.head:
print("List is empty.")
return
if not self.head.next:
self.head = None
return
temp = self.head
while temp.next:
20
temp = temp.next
temp.prev.next = None

def delete_at_position(self, pos):


if not self.head:
print("List is empty.")
return
if pos == 0:
self.delete_at_beginning()
return
temp = self.head
index = 0
while temp and index < pos:
temp = temp.next
index += 1
if temp is None:
print("Position out of range.")
return
if temp.prev:
temp.prev.next = temp.next
if temp.next:
temp.next.prev = temp.prev

def search(self, key):


temp = self.head
pos = 0
while temp:
if temp.data == key:
return pos
temp = temp.next
pos += 1
return -1

def display_forward(self):
temp = self.head
if not temp:
print("List is empty.")
return
while temp:
print(temp.data, end=" <-> ")
21
temp = temp.next
print("None")

def display_backward(self):
temp = self.head
if not temp:
print("List is empty.")
return
while temp.next:
temp = temp.next
while temp:
print(temp.data, end=" <-> ")
temp = temp.prev
print("None")
if name == " main ":
dll = DoublyLinkedList()

while True:
print("\n--- Doubly Linked List Menu ---")
print("1. Insert at beginning")
print("2. Insert at end")
print("3. Insert at position")
print("4. Delete at beginning")
print("5. Delete at end")
print("6. Delete at position")
print("7. Search")
print("8. Display forward")
print("9. Display backward")
print("10. Exit")

choice = int(input("Enter your choice: "))

if choice == 1:
val = int(input("Enter value: "))
dll.insert_at_beginning(val)
dll.display_forward()
elif choice == 2:
val = int(input("Enter value: "))
dll.insert_at_end(val)
dll.display_forward()
22
elif choice == 3:
pos = int(input("Enter position: "))
val = int(input("Enter value: "))
dll.insert_at_position(pos, val)
dll.display_forward()
elif choice == 4:
dll.delete_at_beginning()
dll.display_forward()
elif choice == 5:
dll.delete_at_end()
dll.display_forward()
elif choice == 6:
pos = int(input("Enter position: "))
dll.delete_at_position(pos)
dll.display_forward()
elif choice == 7:
key = int(input("Enter value to search: "))
result = dll.search(key)
if result != -1:
print(f"Element found at position {result}")
else:
print("Element not found.")
elif choice == 8:
dll.display_forward()
elif choice == 9:
dll.display_backward()
elif choice == 10:
print("Exiting...")
break
else:
print("Invalid choice. Try again.")

Output

23
Result:
Thus, the Python program for implementing a Doubly Linked List was executed
successfully and all the operations such as insertion, deletion, search, and
forward/backward traversal were performed and verified.
24
Ex.no.04c Implementations of List using CLL
Date :

Aim:
To implement and perform operations on a Circular Linked List (CLL) including
insertion (at beginning, end, position), deletion (at beginning, end, position), search, and
display using Python.

Algorithm
Node Structure:
Step 1:Create a node with data and a next pointer.
Insert at Beginning:
Step 1: Create a new node.
Step 2 : If list is empty, point new node to itself.
Step 3: Else, traverse to the last node and adjust the head and last node's next.
Insert at End:
Step 1: Similar to beginning but new node is added after the last node.
Insert at Position:
Step 1: Traverse to the node just before the desired position and insert accordingly.
Delete at Beginning:
Step 1: If one node: make head None.
Step 2: Else, point last node's next to the second node and update head.
Delete at End:
Step 1: Traverse to second last node, set its next to head.
Delete at Position:
Step 1: Traverse to the node just before the position and remove the next node.
Search:
Step 1: Traverse and compare each node‘s data with the key.
Display:
Step 1: Start from head, print each node‘s data until you loop back to the head.

Python program
class Node:
def init (self, data):
self.data = data
self.next = None

class CircularLinkedList:
def init (self):
25
self.head = None

def insert_at_end(self, data):


new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = self.head
else:
temp = self.head
while temp.next != self.head:
temp = temp.next
temp.next = new_node
new_node.next = self.head

def insert_at_beginning(self, data):


new_node = Node(data)
if not self.head:
self.head = new_node
new_node.next = self.head
else:
new_node.next = self.head
temp = self.head
while temp.next != self.head:
temp = temp.next
temp.next = new_node
self.head = new_node

def insert_at_position(self, pos, data):


new_node = Node(data)

if pos == 0:
self.insert_at_beginning(data)
return

temp = self.head
index = 0

while temp.next != self.head and index < pos - 1:


temp = temp.next
index += 1
26
if index != pos - 1:
print("Position out of range.")
return

new_node.next = temp.next
temp.next = new_node

def delete_at_beginning(self):
if not self.head:
print("List is empty.")
return
if self.head.next == self.head:
self.head = None
else:
temp = self.head
while temp.next != self.head:
temp = temp.next
temp.next = self.head.next
self.head = self.head.next

def delete_at_end(self):
if not self.head:
print("List is empty.")
return
if self.head.next == self.head:
self.head = None
else:
prev = None
temp = self.head
while temp.next != self.head:
prev = temp
temp = temp.next
prev.next = self.head

def delete_at_position(self, pos):


if not self.head:
print("List is empty.")
return

27
if pos == 0:
self.delete_at_beginning()
return

current = self.head
prev = None
index = 0

while True:
if index == pos:
if prev:
prev.next = current.next
return
prev = current
current = current.next
index += 1
if current == self.head:
print("Position out of range.")
return

def search(self, key):


if not self.head:
return -1
temp = self.head
index = 0
while True:
if temp.data == key:
return index
temp = temp.next
index += 1
if temp == self.head:
break
return -1

def display(self):
if not self.head:
print("List is empty.")
return
temp = self.head
while True:
28
print(temp.data, end=" -> ")
temp = temp.next
if temp == self.head:
break
print("(back to head)")
if name == " main ":
cll = CircularLinkedList()

while True:
print("\n--- Circular Linked List Menu ---")
print("1. Insert at beginning")
print("2. Insert at end")
print("3. Insert at position")
print("4. Delete at beginning")
print("5. Delete at end")
print("6. Delete at position")
print("7. Search")
print("8. Display")
print("9. Exit")

choice = int(input("Enter your choice: "))

if choice == 1:
val = int(input("Enter value: "))
cll.insert_at_beginning(val)
cll.display()
elif choice == 2:
val = int(input("Enter value: "))
cll.insert_at_end(val)
cll.display()
elif choice == 3:
pos = int(input("Enter position: "))
val = int(input("Enter value: "))
cll.insert_at_position(pos, val)
cll.display()
elif choice == 4:
cll.delete_at_beginning()
cll.display()
elif choice == 5:
cll.delete_at_end()
29
cll.display()
elif choice == 6:
pos = int(input("Enter position to delete: "))
cll.delete_at_position(pos)
cll.display()
elif choice == 7:
key = int(input("Enter value to search: "))
result = cll.search(key)
if result != -1:
print(f"Element found at position {result}")
else:
print("Element not found.")
elif choice == 8:
cll.display()
elif choice == 9:
print("Exiting...")
break
else:
print("Invalid choice. Try again.")

Output

30
Result:
Thus, the Python program for Circular Linked List operations was successfully
executed and the output was verified.

31
Ex.no.05a Implementations of stack ADT
Date:

Aim:
To implement a Stack Abstract Data Type (ADT) in Python using a list with the
following operations:
• Push (insert element)
• Pop (remove element)
• Peek (view top element)
• Check if stack is empty
• Check size of the stack
• Display the contents of the stack

Algorithm:
1. Initialization
Step 1: Create an empty list to represent the stack
2. Push Operation
Step 1: Take the input item
Step 2: Use list.append(item) to add item at the end (top of stack)
3. Pop Operation
Step 1: Check if the stack is not empty
Step 2: Use list.pop() to remove and return the top item
Step 3: If stack is empty, return an appropriate message
4. Peek Operation
Step 1: Check if stack is not empty
Step 2: Return the last element using list[-1]
Step 3: If empty, return a message
5. Is_Empty Operation
Step 1: Return True if length of list is 0, else return False
6. Size Operation
Step 1: Return length of the stack list using len()
7. Display Operation
Step 1: Print the list representing the stack

Python program
class Stack:
def init (self):
self.items = []

def push(self, item):


32
self.items.append(item)

def pop(self):
if not self.is_empty():
return self.items.pop()
else:
return "Stack is empty!"

def peek(self):
if not self.is_empty():
return self.items[-1]
else:
return "Stack is empty!"

def is_empty(self):
return len(self.items) == 0

def size(self):
return len(self.items)

def display(self):
print("Stack values are:", self.items)
# Main program with user input
if name == " main ":
stack = Stack()
while True:
print("\n--- Stack Menu ---")
print("1. Push")
print("2. Pop")
print("3. Peek")
print("4. Display")
print("5. Size")
print("6. Exit")
choice = input("Enter your choice (1-6): ")
if choice == '1':
item = input("Enter item to push: ")
stack.push(item)
print(f"{item} pushed onto stack.")

33
elif choice == '2':
result = stack.pop()
print(f"Popped item: {result}")

elif choice == '3':


print(f"Top element: {stack.peek()}")

elif choice == '4':


stack.display()

elif choice == '5':


print(f"Stack size: {stack.size()}")

elif choice == '6':


print("Exiting...")
break
else:
print("Invalid choice! Please select between 1-6.")
Output

34
Result:
Thus, the Python program to implement Stack ADT using a list was executed
successful .& All operations including push, pop, peek, display, size, and is_empty were
tested and verified.

35
Ex.no.5b Implementations of queue ADT
Date:

Aim:
To implement a Queue Abstract Data Type (ADT) using a list in Python with the
following operations:
• Enqueue (insert at rear)
• Dequeue (remove from front)
• Peek (view front element)
• Check if queue is empty
• Check the size of the queue
• Display the contents of the queue

Algorithm:
1. Initialization
Step 1: Create an empty list to represent the queue.
2. Enqueue Operation
Step 1: Accept the input item.
Step 2: Use list.append(item) to insert the item at the rear.
3. Dequeue Operation
Step 1: Check if the queue is not empty.
Step 2: Use list.pop(0) to remove and return the front element.
Step 3: If the queue is empty, display an appropriate message.
4. Peek Operation
Step 1: Check if the queue is not empty.
Step 2: Return the element at index 0 (front of the queue).
Step 3: If empty, return a message.
5. Is_Empty Operation
Step 1: Return True if length of the list is 0; otherwise, return False.
6. Size Operation
Step 1: Return the length of the list using len().
7. Display Operation
Step 1: Print all elements in the list from front to rear.

Python program
class Queue:
def init (self):
self.items = []

def enqueue(self, item):


36
self.items.append(item) # insert at rear

def dequeue(self):
if not self.is_empty():
return self.items.pop(0) # remove from front
else:
return "Queue is empty!"

def peek(self):
if not self.is_empty():
return self.items[0] # front element
else:
return "Queue is empty!"

def is_empty(self):
return len(self.items) == 0

def size(self):
return len(self.items)

def display(self):
print("Queue (front → rear):", self.items)

# Main program with user input


if name == " main ":
queue = Queue()
while True:
print("\n--- Queue Menu ---")
print("1. Enqueue")
print("2. Dequeue")
print("3. Peek")
print("4. Display")
print("5. Size")
print("6. Exit")
choice = input("Enter your choice (1-6): ")

if choice == '1':
item = input("Enter item to enqueue: ")
queue.enqueue(item)
37
print(f"{item} added to queue.")

elif choice == '2':


result = queue.dequeue()
print(f"Dequeued item: {result}")
elif choice == '3':
print(f"Front element: {queue.peek()}")
elif choice == '4':
queue.display()
elif choice == '5':
print(f"Queue size: {queue.size()}")
elif choice == '6':
print("Exiting...")
break
else:
print("Invalid choice! Please select between 1-6.")

Output

38
Result:
Thus, the Python program to implement Queue ADT using a list was successfully
executed & All operations such as enqueue, dequeue, peek, display, is_empty, and size
were tested and verified

39
Ex No:6a Application of List, Stack, Queue
Date:

Application of list text processing

Aim:
To implement a text processing program in Python that accepts user input at runtime
and performs the following operations:
• Converts text to lowercase
• Removes punctuation
• Tokenizes the text into words
• Counts the total number of words
• Calculates the frequency of each word

Algorithm:
Step 1: Start
Step 2: Prompt the user to enter a line of text at runtime.
Step 3: Convert the input text to lowercase using the .lower() method.
Step 4: Remove punctuation from the text using str.translate() with
string.punctuation.
Step 5: Split the cleaned text into a list of words using .split().
Step 6: Count the total number of words using len() function.
Step 7: Use collections.Counter() to count the frequency of each word in the list.
Step 8: Display the following results:
Original text
Cleaned (processed) text
Total number of words
Word frequencies
Step 9: End

Python program
import string
from collections import Counter

# Get text input from the user at runtime


text = input("Enter your text: ")

# Convert to lowercase
text_lower = text.lower()

# Remove punctuation
text_clean = text_lower.translate(str.maketrans('', '', string.punctuation))

# Tokenize into words


40
words = text_clean.split()

# Count total words


total_words = len(words)

# Frequency of each word


word_freq = Counter(words)

# Display results
print("\n--- Text Processing Output ---")
print(f"Original Text: {text}")
print(f"Cleaned Text: {text_clean}")
print(f"Total Words: {total_words}")
print("Word Frequencies:")
for word, freq in word_freq.items():
print(f"{word}: {freq}")

Output:

Result:
Thus the program for implementing the text processing is executed and verified
successfully.
41
Ex.no.6b Application of Queue: Double Ended Queue
Date:

Aim:
To implement a Deque (Double-Ended Queue) data structure in Python and
perform various operations such as insertion and deletion from both the front and rear
ends using runtime input from the user.

Algorithm:

Step 1.Define a class Deque with an empty list items to hold the deque elements.
Step 2.Create the following methods in the Deque class:
is_empty(): Checks if the deque is empty.
add_front(item): Inserts item at the front (beginning) of the deque.
add_rear(item): Inserts item at the rear (end) of the deque.
remove_front(): Removes and returns the item from the front of the deque if it's not
empty.
remove_rear(): Removes and returns the item from the rear of the deque if it's not
empty.
display(): Returns the current elements in the deque.
Step 3.In the main() section, present the user with a menu to:
Add to front
Add to rear
Remove from front
Remove from rear
Display deque
Exit
Step 4.Take the user's choice as input and call the appropriate method based on the
input.
Step 5.Repeat the menu until the user chooses to exit.

Python program
class Deque:
def init (self):
self.items = []

def is_empty(self):
return not self.items

def add_front(self, item):


self.items.insert(0, item)

42
def add_rear(self, item):
self.items.append(item)

def remove_front(self):
if not self.is_empty():
return self.items.pop(0)
else:
return "Deque is empty"

def remove_rear(self):
if not self.is_empty():
return self.items.pop()
else:
return "Deque is empty"

def display(self):
return self.items

# Runtime interaction
if name == " main ":
dq = Deque()

while True:
print("\n--- Deque Menu ---")
print("1. Add to Front")
print("2. Add to Rear")
print("3. Remove from Front")
print("4. Remove from Rear")
print("5. Display Deque")
print("6. Exit")

choice = input("Enter your choice (1-6): ")

if choice == '1':
val = input("Enter value to add at front: ")
dq.add_front(val)
elif choice == '2':
val = input("Enter value to add at rear: ")
dq.add_rear(val)
elif choice == '3':
print("Removed from front:", dq.remove_front())
elif choice == '4':
print("Removed from rear:", dq.remove_rear())
elif choice == '5':
print("Current Deque:", dq.display())
elif choice == '6':
43
print("Exiting...")
break
else:
print("Invalid choice! Please enter 1 to 6.")

Output:

Result:
Thus the program for implementing the double ended queue is executed and
verified successfully.
44
Ex.no.6c Application of Stack : Infix to Postfix Conversion
Date:

Aim:
To implement a Python program that converts a given infix expression to a postfix
expression (Reverse Polish Notation) using a stack, taking input at runtime and
considering operator precedence and parentheses.

Algorithm:
Step 1: Start the program and take the infix expression as input from the user.
Step 2:An empty list stack to store operators and parentheses.
An empty list postfix to build the postfix expression.
Step 3: Loop through each character ch in the infix expression:
If ch is an operand (letter or digit), append it directly to the postfix list.
Step 4: If ch is an opening parenthesis '(', push it onto the stack.
Step 5: If ch is a closing parenthesis ')':
Pop from the stack and append to postfix until '(' is encountered.
Discard the '('.
Step 6: If ch is an operator (+, -, *, /, ^):
While the stack is not empty and the operator on top has higher or equal
precedence, pop it and append to postfix.
Push the current operator onto the stack.
Step 7: After the loop, pop all remaining operators from the stack and append them to
the postfix list.
Step 8: Join the postfix list into a single string to form the final expression.
Step 9: Print the postfix expression.
Step 10: End the program.

Python program
class InfixToPostfixConverter:
def init (self):
self.stack = []
self.postfix = []
self.precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}

def is_operator(self, ch):


return ch in self.precedence

def higher_precedence(self, op1, op2):


return self.precedence[op1] >= self.precedence[op2]

def convert(self, infix):


for ch in infix:
45
if ch.isalnum(): # operand
self.postfix.append(ch)
elif ch == '(':
self.stack.append(ch)
elif ch == ')':
while self.stack and self.stack[-1] != '(':
self.postfix.append(self.stack.pop())
self.stack.pop() # pop '('
elif self.is_operator(ch):
while (self.stack and self.stack[-1] != '(' and
self.higher_precedence(self.stack[-1], ch)):
self.postfix.append(self.stack.pop())
self.stack.append(ch)

while self.stack:
self.postfix.append(self.stack.pop())

return ''.join(self.postfix)

if name == " main ":


infix_expr = input("Enter an infix expression: ")
converter = InfixToPostfixConverter()
postfix_expr = converter.convert(infix_expr)
print("Postfix expression:", postfix_expr)

Output:

Result:
Thus the program for conversion of infix to postfix expression is executed and
verified successfully.
46
Ex No: 7a Implementation of Sorting and Searching Algorithms
Date:

a)Bubble Sort:
Aim:
To implement the Bubble Sort algorithm in Python that takes user input at
runtime, sorts the list of numbers in ascending order, and displays the sorted result.

Algorithm:
Step 1: Start the program and define a function bubble_sort(arr) to perform sorting.
Step 2: Inside the function, calculate the length n of the list arr.
Step 3: Run an outer loop i from 0 to n - 1 to iterate through all elements.
Step 4: For each pass, run an inner loop j from 0 to n - i - 1:
This ensures the last i elements are already sorted and don't need comparison.
Step 5: Inside the inner loop, compare adjacent elements:
If arr[j] > arr[j + 1], swap them.
Step 6: Continue this process until no more swaps are needed, ensuring the list is
sorted.
Step 7: In the main block, take space-separated numbers as input from the user
using input().
Step 8: Convert the input string into a list of integers using map() and split().
Display the original unsorted list.
Step 9: Call the bubble_sort() function to sort the list, then print the sorted list.

Python program
def bubble_sort(arr):
n = len(arr)
for i in range(n):
# Last i elements are already sorted
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
# Swap
arr[j], arr[j + 1] = arr[j + 1], arr[j]

# Take input from user at runtime


input_str = input("Enter numbers separated by space: ")
# Convert input string to list of integers
numbers = list(map(int, input_str.split()))
print("Original list:", numbers)
bubble_sort(numbers)
print("Sorted list:", numbers)

47
Output:

Result:
Thus the program for implementing the Bubble sort is executed and verified
successfully.
48
Ex No: 7b Implementation of merge sort using python
Date :

Aim:
To implement the Merge Sort algorithm in Python to sort a list of integers entered
by the user at runtime.

Algorithm:
Step 1: Start.
Step 2: Take input from the user as a list of integers (space-separated).
Step 3: Define a recursive function merge_sort(arr) to perform the sorting:
Step 4: If the length of arr is greater than 1:
Find the middle index to divide the array into two halves: left_half and
right_half.
Recursively call merge_sort on both halves.
Initialize three indices:
i for traversing left_half
j for traversing right_half
k for placing sorted elements back into arr
Compare elements of both halves and copy the smaller one into arr.
After the loop, if any elements are left in left_half or right_half, copy
them into arr.
Step 5: Print the original array.
Step 6: Call merge_sort(arr) to sort the array.
Step 7: Print the sorted array.
Step 8: End of the program.

Python program
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2 # Finding the middle of the array
left_half = arr[:mid] # Dividing the array elements
right_half = arr[mid:]

merge_sort(left_half) # Sorting the first half


merge_sort(right_half) # Sorting the second half

i=j=k=0

# Merging the two halves


while i < len(left_half) and j < len(right_half):
if left_half[i] < right_half[j]:
arr[k] = left_half[i]
49
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1

# Checking for any leftover elements


while i < len(left_half):
arr[k] = left_half[i]
i += 1
k += 1

while j < len(right_half):


arr[k] = right_half[j]
j += 1
k += 1

# Get user input at runtime


user_input = input("Enter numbers separated by spaces: ")
arr = list(map(int, user_input.split()))

print("Original array:", arr)


merge_sort(arr)
print("Sorted array:", arr)

Output:

Result:
Thus the program for implementing the merge sort is executed and verified
successfully.
50
Ex No: 7c Implementation of Linear Search:
Aim:
To implement a Linear Search algorithm in Python that allows the user to input
a list of elements at runtime and search for a target element within that list.

Algorithm:
Step 1: Start the program.
Step 2: Accept a list of elements from the user as a single line of input (e.g., numbers
separated by spaces).
Step 3: Split the input string into individual elements and convert them into integers
(or another data type as required).
Step 4: Store the elements in a list or array called arr.
Step 5: Prompt the user to enter the element they want to search for (the target
value).
Step 6: Define a function linear_search(arr, target) to perform the search.
Step 7: Traverse the list from the beginning to the end using a loop (e.g., for i in
range(len(arr))).
Step 8: Compare each element in the list with the target value.
Step 9: If a match is found, return the index of the element. If no match is found
after the loop, return -1.
Step 10: Display the result: If the index is found, print the position; otherwise, state
that the element is not found.

Python program
def linear_search(arr, target):
for i in range(len(arr)):
if arr[i] == target:
return i # Return the index where the target is found
return -1 # Return -1 if the target is not found

# Get input from user at runtime


elements = input("Enter elements separated by spaces: ").split()
arr = [int(x) for x in elements] # Convert input strings to integers

target = int(input("Enter the element to search for: "))

# Perform linear search


result = linear_search(arr, target)

# Display the result


if result != -1:
print(f"Element found at index {result}")
else:
print("Element not found in the list")
51
Output:

Result:
Thus the program for implementing the linear search is executed and verified
successfully.

52
Ex No: 7d Implementation of Binary Search :
Date :
Aim:
To implement Binary Search in Python to search for an element in a sorted list
entered by the user at runtime.

Algorithm:
Step 1: Start the program.
Step 2: Input a list of sorted elements (in ascending order) from the user.
Step 3: Convert the input string into a list of integers using split() and map().
Step 4: Input the target element to be searched from the user.
Step 5: Initialize two pointers: low = 0 and high = len(arr) - 1.
Step 6: Use a while loop that continues as long as low <= high.
Step 7: Calculate the middle index: mid = (low + high) // 2.
Step 8: If the middle element arr[mid] equals the target:
Return the index (mid) — element found.
Step 9: If arr[mid] < target, search in the right half (low = mid + 1),
else search in the left half (high = mid - 1).
Step 10: If the loop ends without finding the element, return -1 — element not
found.

Python program
def binary_search(arr, target):
low = 0
high = len(arr) - 1

while low <= high:


mid = (low + high) // 2

if arr[mid] == target:
return mid # Target found, return index
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1

return -1 # Target not found

# Get input from user at runtime


elements = input("Enter sorted elements separated by spaces: ")
arr = list(map(int, elements.split()))
target = int(input("Enter the element to search for: "))

# Perform binary search


53
result = binary_search(arr, target)

# Display result
if result != -1:
print(f"Element {target} found at index {result}")
else:
print(f"Element {target} not found in the list")

Output:

Result:
Thus the program for implementing the binary search is executed and verified
successfully.
54
Ex No:8 Implementation of hash table using python
Date:

Aim:
To implement a hash table with chaining (using lists) in Python that allows users to
insert, search, delete, and display key-value pairs through runtime input.

Algorithm:
Step 1: Start the program by defining a Hash Table class that takes a size for the
table.
Step 2: Inside init (), create a list of empty buckets (lists) to handle collisions
using chaining.
Step 3:
Use Python's built-in hash() function.
Compute index as hash(key) % size.
Step 4:
Compute index using the hash function.
Check if the key already exists in the bucket.
If found, update the value.
Else, append the new [key, value] pair.
Step 5: Define search(key):
Compute the index using the hash function.
Traverse the bucket at that index to find the key.
Return the value if found; otherwise return None.
Step 6: Define delete(key):
Compute the index using the hash function.
Traverse the bucket to find and remove the key-value pair.
Return True if deleted; else False.
Step 7: Define display():
Loop through each index and print the contents (buckets) of the hash table.
Step 8: In the main() function:
Take table size as input from the user.
Create an instance of the HashTable with the given size.
Step 9: Display a menu with options (Insert, Search, Delete, Display, Exit) and take
user input in a loop.
Step 10: Perform operations based on user choice and repeat until the user chooses to
exit.

Python program
class HashTable:
def init (self, size):
self.size = size
self.table = [[] for _ in range(size)]

def hash_function(self, key):


return hash(key) % self.size
55
def insert(self, key, value):
index = self.hash_function(key)
# Check if key already exists, update value
for item in self.table[index]:
if item[0] == key:
item[1] = value
return
self.table[index].append([key, value])

def search(self, key):


index = self.hash_function(key)
for item in self.table[index]:
if item[0] == key:
return item[1]
return None

def delete(self, key):


index = self.hash_function(key)
for i, item in enumerate(self.table[index]):
if item[0] == key:
del self.table[index][i]
return True
return False

def display(self):
for i, bucket in enumerate(self.table):
print(f"Index {i}: {bucket}")

# ---- Runtime interaction ----- #


def main():
size = int(input("Enter size of the hash table: "))
ht = HashTable(size)

while True:
print("\nMenu:")
print("1. Insert")
print("2. Search")
print("3. Delete")
print("4. Display")
print("5. Exit")

choice = int(input("Enter your choice: "))

if choice == 1:
56
key = input("Enter key: ")
value = input("Enter value: ")
ht.insert(key, value)
elif choice == 2:
key = input("Enter key to search: ")
result = ht.search(key)
print(f"Value: {result}" if result else "Key not found")
elif choice == 3:
key = input("Enter key to delete: ")
result = ht.delete(key)
print("Deleted successfully" if result else "Key not found")
elif choice == 4:
ht.display()
elif choice == 5:
print("Exiting...")
break
else:
print("Invalid choice!")

if name == " main ":


main()

Output:

57
Result:
Thus the program for implementing the hash table is executed and verified
successfully.

58
Ex.no.09a Array Representation of Tree
Date:
Aim:
To implement a binary tree using array representation in Python and perform
insert and display operations.

Algorithm
Step 1: Start.
Step 2: Initialize a list of fixed size with None values to simulate the binary tree array.
Step 3: Set a variable last_index = -1 to track the last inserted index.
Step 4: For each insert(value):
• If last_index + 1 < size, insert value at last_index + 1 and update last_index.
• Else, print ―Tree is full‖.
Step 5: For display():
• Traverse the array and print non-None values with their index.
Step 6: End.

Python program
class BinaryTreeArray:
def init (self, size):
self.tree = [None] * size
self.last_index = -1

def insert(self, value):


if self.last_index + 1 < len(self.tree):
self.last_index += 1
self.tree[self.last_index] = value
else:
print("Tree is full!")

def display(self):
print("Tree as array:")
for i, val in enumerate(self.tree):
if val is not None:
print(f"Index {i}: {val}")

# ---------- Main Program ----------


btree = BinaryTreeArray(10)
btree.insert('A')
btree.insert('B')
59
btree.insert('C')
btree.insert('D')
btree.insert('E')
btree.insert('F')
btree.display()

Output

Result:
Thus, the program for array representation of a binary tree was implemented
successfully and the insert and display operations were executed and the output was
verified.
60
Ex.no.09b Tree Representation and Traversal Algorithms
Date:
Aim:
To develop a python program to perform tree representation and traversals
including In-order, Pre-order, Post-order, and Level-order traversals.

Algorithm:

Step 1: Start the program.


Step 2: Read the number of vertices and vertex names.
Step 3: Initialize an adjacency list to store the graph.
Step 4: Read edges with weights and add them to the graph (undirected).
Step 5: Define prim() function:

• Initialize an empty MST list and visited set.


• Use a min-heap to select the minimum weight edge at each step.
• Repeat until all vertices are visited.
• Add selected edges to MST and calculate total cost.
Step 6: Call the prim() function with the starting vertex.
Step 7: Display the edges in the MST and total cost.
Step 8: Stop the program.

Python Program:

from collections import deque

# Node class
class Node:
def init (self, data):
self.data = data
self.left = None
self.right = None

# Binary Tree class


class BinaryTree:
def init (self):
self.root = None

def insert(self, data): # Level-order insertion


new_node = Node(data)
61
if not self.root:
self.root = new_node
return
queue = deque([self.root])
while queue:
temp = queue.popleft()
if not temp.left:
temp.left = new_node
return
else:
queue.append(temp.left)
if not temp.right:
temp.right = new_node
return
else:
queue.append(temp.right)

def inorder(self, node): # In-order traversal


if node:
self.inorder(node.left)
print(node.data, end=' ')
self.inorder(node.right)

def preorder(self, node): # Pre-order traversal


if node:
print(node.data, end=' ')
self.preorder(node.left)
self.preorder(node.right)

def postorder(self, node): # Post-order traversal


if node:
self.postorder(node.left)
self.postorder(node.right)
print(node.data, end=' ')

def level_order(self): # Level-order traversal


if not self.root:
return
queue = deque([self.root])
while queue:
62
node = queue.popleft()
print(node.data, end=' ')
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)

def search(self, node, key): # Search


if not node:
return False
if node.data == key:
return True
return self.search(node.left, key) or self.search(node.right, key)

def display(self, node, level=0, prefix="Root: "): # Horizontal tree display


if node is not None:
print(" " * (level * 4) + prefix + str(node.data))
if node.left or node.right:
self.display(node.left, level + 1, prefix="L--- ")
self.display(node.right, level + 1, prefix="R--- ")

# Main program
tree = BinaryTree()
n = int(input("Enter number of nodes to insert: "))
for _ in range(n):
val = int(input("Enter node value: "))
tree.insert(val)

print("\nBinary Tree Structure:")


tree.display(tree.root)

print("\nTree Traversals:")
print("In-order: ", end=''); tree.inorder(tree.root)
print("\nPre-order: ", end=''); tree.preorder(tree.root)
print("\nPost-order: ", end=''); tree.postorder(tree.root)
print("\nLevel-order: ", end=''); tree.level_order()

search_val = int(input("\n\nEnter value to search in tree: "))


found = tree.search(tree.root, search_val)
print("Result:", "Found" if found else "Not Found")
63
Output

Result:
Thus the Tree representation and traversal in Python program was successfully
executed and the output was verified.

64
Ex.no.10 Implementations of AVL trees
Date :

Aim
To implement an AVL Tree in Python with insertion, self-balancing using
rotations (LL, RR, LR, RL), and display Preorder, In order traversals, and balance factors
of each node.

Algorithm

Step 1: Start the program.


Step 2: Define a Node class with attributes: key, left child, right child, and height.
Step 3: Define an AVL Tree class with methods for getting height, balance factor,
rotations (left and right), insertion, and traversals.
Step 4: Get space-separated integers from the user as input.
Step 5: For each element in the input list, insert the element into the AVL tree using the
insert function.
Step 6: During insertion, check the balance factor at each node and perform rotations if
required to maintain AVL property.
Step 7: After insertion is complete, perform and display:

• Preorder traversal of the AVL tree.


• Inorder traversal of the AVL tree.
• Balance factor of each node.
Step 8: Stop the program.

Python Program:
# Node class for AVL Tree
class Node:
def init (self, key):
self.key = key
self.left = None
self.right = None
self.height = 1

65
# AVL Tree class
class AVLTree:
def get_height(self, node):
return 0 if not node else node.height
def get_balance(self, node):
return 0 if not node else self.get_height(node.left) - self.get_height(node.right)

def right_rotate(self, y):


x = y.left
T2 = x.right

x.right = y
y.left = T2

# Update heights
y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))
x.height = 1 + max(self.get_height(x.left), self.get_height(x.right))
return x

def left_rotate(self, x):


y = x.right
T2 = y.left

y.left = x
x.right = T2

# Update heights
x.height = 1 + max(self.get_height(x.left), self.get_height(x.right))
y.height = 1 + max(self.get_height(y.left), self.get_height(y.right))
return y

def insert(self, root, key):


# 1. Perform normal BST insertion
if not root:
return Node(key)
elif key < root.key:
root.left = self.insert(root.left, key)
elif key > root.key:
root.right = self.insert(root.right, key)
else:
66
print(f"Duplicate key {key} not allowed.")
return root

# 2. Update height
root.height = 1 + max(self.get_height(root.left), self.get_height(root.right))

# 3. Get balance factor


balance = self.get_balance(root)

# 4. Balance the tree using rotations

# Left Left Case


if balance > 1 and key < root.left.key:
return self.right_rotate(root)

# Right Right Case


if balance < -1 and key > root.right.key:
return self.left_rotate(root)

# Left Right Case


if balance > 1 and key > root.left.key:
root.left = self.left_rotate(root.left)
return self.right_rotate(root)

# Right Left Case


if balance < -1 and key < root.right.key:
root.right = self.right_rotate(root.right)
return self.left_rotate(root)
return root
# Preorder traversal: Root -> Left -> Right
def preorder(self, root):
if root:
print(root.key, end=' ')
self.preorder(root.left)
self.preorder(root.right)

# Inorder traversal: Left -> Root -> Right


def inorder(self, root):
if root:
self.inorder(root.left)
67
print(root.key, end=' ')
self.inorder(root.right)
# Optional: Print balance factor of each node
def print_balance_factors(self, root):
if root:
self.print_balance_factors(root.left)
print(f"Node {root.key} → BF = {self.get_balance(root)}")
self.print_balance_factors(root.right)

#
# Main block for runtime input
if name == " main ":
tree = AVLTree()
root = None
print("Enter space-separated integers to insert into AVL Tree:")
elements = list(map(int, input().split()))
for key in elements:
root = tree.insert(root, key)
print("\nPreorder Traversal (Root → Left → Right):")
tree.preorder(root)
print("\n\nInorder Traversal (Left → Root → Right):")
tree.inorder(root)
print("\n\nBalance Factors of Nodes:")
tree.print_balance_factors(root)

Output:

68
Result:
Thus the AVL Tree implementation in Python was successfully executed and the
output was verified as correct.

69
Ex.no.11a Representation of Graph as Adjacency list
Date :

Aim:

To implement an undirected graph using an adjacency list in Python and display its
structure.

Algorithm:
Step 1: Start the program.
Step 2: Define a function add_edge(adj, i, j) to add an edge between two
vertices i and j.
• Append j to the adjacency list of i.
• Append i to the adjacency list of j (since the graph is undirected).
Step 3: Define a function display_adj_list(adj) to print the adjacency list:
• For each vertex, print its list of adjacent vertices.
Step 4: Create an empty adjacency list with the required number of vertices.
Step 5: Add edges to the graph by calling the add_edge() function.
Step 6: Call display_adj_list() to display the graph.
Step 7: Stop the program.

Python Program:
def add_edge(adj, i, j):
adj[i].append(j)
adj[j].append(i) # Undirected

def display_adj_list(adj):
for i in range(len(adj)):
print(f"{i}: ", end='')
for j in adj[i]:
print(j, end=' ')
print()

# Main
V=4
adj = [[] for _ in range(V)]
# Adding edges
add_edge(adj, 0, 1)
add_edge(adj, 0, 2)
add_edge(adj, 1, 2)
70
add_edge(adj, 2, 3)
print("Adjacency List Representation:")
display_adj_list(adj)

Output:

Result:
The Python program to represent an undirected graph using an adjacency list
was successfully executed .

71
Ex.no.11b Representation of Graph as Adjacency Matrix
Date:

Aim:
To implement an undirected graph using an adjacency matrix in Python and
display its structure.

Algorithm:

Step 1: Start the program.


Step 2: Initialize the number of vertices V.
Step 3: Create a V × V matrix (2D list) and initialize all entries to 0.
Step 4: Define a function add_edge(matrix, i, j):
• Set matrix[i][j] = 1 and matrix[j][i] = 1 since the graph is
undirected.
Step 5: Define a function display_matrix(matrix):
• Traverse the matrix row by row and print its contents.
Step 6: Add edges to the graph by calling add_edge() with appropriate vertex pairs.
Step 7: Call display_matrix() to print the adjacency matrix.
Step 8: Stop the program.

Python Program:

def add_edge(matrix, I, j):


matrix[i][j] = 1
matrix[j][i] = 1 # Undirected graph

def display_matrix(matrix):
for row in matrix:
print(‗ ‗.join(map(str, row)))

# Main
V=4
matrix = [[0 for _ in range(V)] for _ in range(V)]
# Adding edges
add_edge(matrix, 0, 1)
add_edge(matrix, 0, 2)
add_edge(matrix, 1, 2)
72
add_edge(matrix, 2, 3)
print(―Adjacency Matrix Representation:‖)
display_matrix(matrix)
Output:

Result:
The Python program to represent an undirected graph using an adjacency matrix
was successfully executed .

73
Ex.no.11c Graph Traversal – Depth First Search
Date :

Aim:
To implement the Depth-First Search (DFS) traversal algorithm in Python.

Algorithm:

Step 1: Start the program.


Step 2: Define a Graph class to hold the graph dictionary.
Step 3: Initialize the graph as an adjacency list using a dictionary where each key is a
node and the value is a set of adjacent nodes.
Step 4: Define a recursive function dfs(graph, start, visited):

• If visited set is not provided, initialize it.


• Mark the current node start as visited and print it.
• For each unvisited neighbor of the current node:
o Recursively call dfs() on the neighbor.

Step 5: Create a sample graph with vertices and edges using a dictionary of sets.
Step 6: Call dfs() with the graph and a starting node.
Step 7: Stop the program.

Python Program:
class graph:
def init (self,gdict=None):
if gdict is None:
gdict = {}
self.gdict = gdict
# Check for the visisted and unvisited nodes
def dfs(graph, start, visited = None):
if visited is None:
visited = set()
visited.add(start)
print(start)
for next in graph[start] - visited:
74
dfs(graph, next, visited)
return visited

gdict = {
"a" : set(["b","c"]),
"b" : set(["a", "d"]),
"c" : set(["a", "d"]),
"d" : set(["e"]),
"e" : set(["a"])
}
dfs(gdict, 'a')

Output:

Result:
Thus the Python program to perform Depth-First Search (DFS) on a graph was
successfully executed and the output was verified.

75
Ex.no.11d Graph Traversal – Breadth First Search
Date :
Aim:
To implement the Breadth-First Search (BFS) traversal algorithm in Python.

Algorithm:

Step 1: Start the program.


Step 2: Define a graph class to store the graph dictionary structure.
Step 3: Initialize the graph using an adjacency list where each node points to a set of its
neighbors.
Step 4: Define the bfs(graph, startnode) function:

• Create a seen set to track visited nodes.


• Create a queue (using collections.deque) and add the
startnode.
• While the queue is not empty:
o Pop the first element and mark it as visited (print it).
o For each unvisited neighbor of the current node:
▪ Add it to the seen set and enqueue it.

Step 5: Define a helper function marked(n) to print visited nodes.


Step 6: Create a sample graph as a dictionary of sets and call bfs() with a start node.
Step 7: Stop the program.

Python Program:
import collections
class graph:
def init (self,gdict=None):
if gdict is None:
gdict = {}
self.gdict = gdict
def bfs(graph, startnode):
# Track the visited and unvisited nodes using queue
seen, queue = set([startnode]), collections.deque([startnode])
76
while queue:
vertex = queue.popleft()
marked(vertex)
for node in graph[vertex]:
if node not in seen:
seen.add(node)
queue.append(node)

def marked(n):
print(n)

# The graph dictionary


gdict = {
"a" : set(["b","c"]),
"b" : set(["a", "d"]),
"c" : set(["a", "d"]),
"d" : set(["e"]),
"e" : set(["a"])
}
bfs(gdict, "a")

Output:

Result:
Thus the Python program for Breadth-First Search (BFS) traversal of a graph was
successfully executed and the output was verified.
77
Ex.no.12a Implementation of Minimum Spanning Tree Algorithm – Kruskal’s
Date : Algorithm
Aim:

To implement Kruskal‘s Algorithm in Python to find the Minimum Spanning Tree


(MST) of a connected, undirected, weighted graph using a Disjoint Set (Union-Find) data
structure.

Algorithm:

Step 1: Start the program.


Step 2: Create a DisjointSet class to manage disjoint sets:

• Initialize each vertex as its own parent.


• Implement find() with path compression to find the root of a set.
• Implement union() to merge two different sets.

Step 3: Define the kruskal() function:

• Accept a list of vertices and a list of edges in the format (u, v, weight).
• Sort the edges in non-decreasing order of their weights.
• Initialize an empty list for MST and a variable for total weight.

Step 4: For each edge in sorted order:

• If the source and destination vertices belong to different sets:


o Add the edge to the MST.
o Merge the sets using union().
o Add the edge weight to the total cost.

Step 5: Return the list of MST edges and total weight.


Step 6: Print the edges included in the MST and the total weight.
Step 7: Stop the program.

Python Program:

class DisjointSet:
def init (self, vertices):
self.parent = {v: v for v in vertices}

def find(self, item):


78
if self.parent[item] != item:
self.parent[item] = self.find(self.parent[item]) # Path compression
return self.parent[item]

def union(self, set1, set2):


root1 = self.find(set1)
root2 = self.find(set2)
if root1 != root2:
self.parent[root2] = root1

def kruskal(vertices, edges):


ds = DisjointSet(vertices)
mst = []
total_weight = 0

edges.sort(key=lambda x: x[2]) # Sort by weight

for u, v, weight in edges:


if ds.find(u) != ds.find(v):
ds.union(u, v)
mst.append((u, v, weight))
total_weight += weight

return mst, total_weight

79
# Sample Input
vertices = ['A', 'B', 'C', 'D', 'E']
edges = [
('A', 'B', 1),
('A', 'C', 3),
('B', 'C', 1),
('B', 'D', 6),
('C', 'D', 4),
('C', 'E', 2),
('D', 'E', 5)
]
mst_edges, total = kruskal(vertices, edges)
# Output
print("Minimum Spanning Tree edges:")
for u, v, weight in mst_edges:
print(f"{u} - {v} : {weight}")
print("Total Weight of MST:", total)

Output

Result:

The Python program to implement Kruskal’s Algorithm using the Disjoint Set
(Union-Find) technique was successfully executed.

80
Ex.no.12b Implementation of Minimum Spanning Tree Algorithm – Prim’s
Date : Algorithm
Date :

Aim:

To implement Prim‘s Algorithm in Python using a priority queue (min-heap) to


construct the Minimum Spanning Tree (MST).

Algorithm:

Step 1: Start the program.


Step 2: Read the number of vertices and their names.
Step 3: Initialize an adjacency list to represent the undirected weighted graph.
Step 4: Read the number of edges and their details: source, destination, and weight.
Step 5: Define the prim() function:

• Initialize an empty set visited, a list mst for storing MST edges, and
total_cost = 0.
• Use a min-heap to store edges in the format (weight, to_vertex,
from_vertex).
• Push the start vertex into the heap with weight 0.

Step 6: While the heap is not empty:

• Pop the edge with the minimum weight.


• If the destination vertex is not visited:
o Add it to visited.
o If the edge is valid (has a parent), add it to mst and update the
total_cost.
o Push all unvisited adjacent vertices to the heap.

Step 7: Return the MST edges and total cost.


Step 8: Print the edges in the MST and the total cost.
Step 9: Stop the program.

81
Python program

import heapq
def prim(graph, start):
visited = set()
mst = []
total_cost = 0

# Min-heap to store (weight, current_vertex, neighbor)


edges = [(0, start, None)] # weight, to_vertex, from_vertex

while edges:
weight, u, parent = heapq.heappop(edges)
if u in visited:
continue

visited.add(u)
if parent is not None:
mst.append((parent, u, weight))
total_cost += weight

for v, w in graph[u]:
if v not in visited:
heapq.heappush(edges, (w, v, u))

return mst, total_cost


# Input graph as adjacency list
graph = {}
print("Enter number of vertices:")
n = int(input())

print("Enter vertex names (space-separated):")


vertices = input().split()

for v in vertices:
graph[v] = []

print("Enter number of edges:")


e = int(input())
print("Enter edges in format: source destination weight")

82
for _ in range(e):
u, v, w = input().split()
w = int(w)
graph[u].append((v, w))
graph[v].append((u, w)) # Undirected graph

start = input("Enter start vertex: ")


mst_edges, cost = prim(graph, start)

print("\nMinimum Spanning Tree edges:")


for u, v, w in mst_edges:
print(f"{u} - {v} : {w}")
print("Total cost of MST:", cost)

Output

83
Result:

Thus the Python program to implement Prim‘s Algorithm for finding the Minimum
Spanning Tree was successfully executed and the output was verified.

84
Ex. No: 13a Advanced Experiments
Date:

Dynamic Memory Allocation with Free List Managed by Heap


Aim:
To simulate dynamic memory allocation in Python using a free list and a heap-like
structure, allowing users to allocate and free memory blocks at runtime, and efficiently
manage available memory through merging adjacent free blocks.

Algorithm:
Step 1:Initialize Memory:
Create a simulated heap as a list of fixed size (e.g., 100 units).
Add one large block to the free list representing the entire free memory.
Step 2:MemoryBlock Structure:
Define a MemoryBlock class with start (address) and size to represent memory
chunks.
Step 3:Allocation Request:
On user input, search the free list for a block large enough to fulfill the request.
Step 4:Allocate Block:
If a suitable block is found:
Assign the requested memory from the block‘s start.
Adjust or remove the block from the free list.
Store allocation details in a dictionary (allocated_blocks).
Step 5:Allocation Failure:
If no block can fulfill the request, print an "Allocation failed" message.
Step 6:Free Request:
On user input to free memory, validate the given address exists in allocated
blocks.
Step 7:Free Memory Block:
Remove the allocation record and add the freed block back into the free list.
Step 8:Merge Free Blocks (Coalescing):
Sort the free list by start address.
Merge adjacent blocks to avoid fragmentation.
Step 9:Display Status:
Allow users to view current free and allocated blocks for monitoring memory
usage.
Step 10:Loop for Runtime Interaction:
Provide a user menu to repeatedly allocate, free, view memory, or exit the program.

85
Python program
class MemoryBlock:
def init (self, start, size):
self.start = start
self.size = size

def repr (self):


return f"Block(start={self.start}, size={self.size})"

class MemoryAllocator:
def init (self, heap_size):
self.heap = [None] * heap_size # Simulated heap memory
self.free_list = [MemoryBlock(0, heap_size)] # Initially one big free block
self.allocated_blocks = {} # Track allocated blocks

def allocate(self, size):


for i, block in enumerate(self.free_list):
if block.size >= size:
start_address = block.start
self.allocated_blocks[start_address] = size

# Adjust the free block


if block.size == size:
self.free_list.pop(i)
else:
block.start += size
block.size -= size

print(f"Allocated {size} units at address {start_address}")


return start_address

print("Allocation failed: Not enough memory")


return None

def free(self, address):


if address not in self.allocated_blocks:
print(f"Invalid free: No allocation found at address {address}")
return

size = self.allocated_blocks.pop(address)
86
new_block = MemoryBlock(address, size)
self.free_list.append(new_block)
self.merge_free_blocks()
print(f"Freed {size} units from address {address}")

def merge_free_blocks(self):
self.free_list.sort(key=lambda block: block.start)
merged = []
for block in self.free_list:
if merged and merged[-1].start + merged[-1].size == block.start:
merged[-1].size += block.size
else:
merged.append(block)
self.free_list = merged

def show_memory(self):
print("\nFree List:", self.free_list)
print("Allocated Blocks:", self.allocated_blocks)
print("-" * 40)

#
# Runtime Interaction
#

if name == " main ":


allocator = MemoryAllocator(100) # Simulated heap of 100 units

while True:
print("\n1. Allocate Memory")
print("2. Free Memory")
print("3. Show Memory")
print("4. Exit")

choice = input("Enter your choice: ")

if choice == '1':
size = int(input("Enter size to allocate: "))
allocator.allocate(size)
elif choice == '2':
address = int(input("Enter address to free: "))
87
allocator.free(address)
elif choice == '3':
allocator.show_memory()

elif choice == '4':


break

else:
print("Invalid choice.")

Output:

88
Result:
Thus the program for implementing Dynamic Memory Allocation with Free List
Managed by Heap is executed and verified successfully.

89
Ex.No:13b Graph Attention Network (GAT) Simulation on Network Graph
Date:

Aim:
To simulate a Graph Attention Network (GAT) in Python that accepts graph
structure and node features at runtime, processes the graph using attention
mechanisms, and outputs node-level embeddings for tasks such as classification or
analysis.

Algorithm :
Step 1: Start the program and prompt the user to input the number of nodes in the
graph.
Step 2: Collect node features at runtime by asking the user to enter feature vectors
for each node.
Step 3: Prompt for the number of edges and take edge connections (source and
destination nodes) as input.
Step 4: Convert the input features and edges into PyTorch tensors suitable for
processing.
Step 5: Construct the graph object using torch_geometric.data.Data, containing x
(features) and edge_index.
Step 6: Define the GAT model architecture using torch_geometric.nn.GATConv
layers with attention heads.
Step 7: Pass the data through the GAT model to compute updated node
embeddings using attention mechanisms.
Step 8: Apply activation functions (e.g., ELU) and pass data through multiple GAT
layers for richer representations.
Step 9: Output the final node embeddings or logits from the GAT model to show
how each node is represented.
Step 10: Optionally visualize the graph structure using network x to understand the
connectivity and layout.

Python program
import torch
from torch.nn import functional as F
from torch_geometric.nn import GATConv
from torch_geometric.data import Data
import networkx as nx
import matplotlib.pyplot as plt

90
# 1. Get input at runtime
num_nodes = int(input("Enter number of nodes: "))
features = []
for i in range(num_nodes):
f = list(map(float, input(f"Enter features for node {i} (space-separated): ").split()))
features.append(f)

num_edges = int(input("Enter number of edges: "))


edge_list = []
for _ in range(num_edges):
src, dst = map(int, input("Enter edge (src dst): ").split())
edge_list.append([src, dst])

# Convert to tensors
x = torch.tensor(features, dtype=torch.float)
edge_index = torch.tensor(edge_list, dtype=torch.long).t().contiguous()

# 2. Create graph data


data = Data(x=x, edge_index=edge_index)

# 3. Define GAT Model


class GAT(torch.nn.Module):
def init (self, in_channels, out_channels):
super(GAT, self). init ()
self.gat1 = GATConv(in_channels, 8, heads=2)
self.gat2 = GATConv(8*2, out_channels, heads=1)

def forward(self, data):


x, edge_index = data.x, data.edge_index
x = F.elu(self.gat1(x, edge_index))
x = self.gat2(x, edge_index)
return x

model = GAT(in_channels=len(features[0]), out_channels=2)


out = model(data)

# 4. Output
print("Node embeddings / output:")
print(out)

91
# Optional: Draw the graph
G = nx.Graph()
G.add_edges_from(edge_list)
nx.draw(G, with_labels=True)
plt.show()

Output:

Result:
Thus the program for designing Graph Attention Network (GAT) Simulation on
Network Graph is executed and verified successfully.

92
Design Experiments

Ex.No: 14a Design and Implementation of a Peer-to-Peer Communication System

Date: Using Graph Search

Aim
To simulate a peer-to-peer (P2P) network using graph representations, where
each node (peer) can communicate with others by searching paths using DFS/BFS
traversal algorithms.

Abstract:
This project simulates a Peer-to-Peer (P2P) communication system using graph
search techniques in Python. Each peer in the network is represented as a node in a graph,
and connections between them are modeled as edges. The system uses depth-first search
(DFS) to check reachability between peers and breadth-first search (BFS) to find the
shortest communication path. This project demonstrates practical applications of graph
traversal algorithms in real-world networking scenarios.

Introduction:
Peer-to-peer networks are decentralized networks where each peer acts as both a
client and a server. These networks are used in file sharing, messaging, blockchain, and
more. Efficient routing and search in such networks are essential. Graph theory provides a
powerful tool for modeling these networks. By implementing graph search algorithms, we
can simulate and test communication routes in a P2P network.

Objectives:
• Model a P2P network using graph representations.
• Implement DFS to check if one peer can reach another.
• Implement BFS to find the shortest path between peers.
• Provide a menu-driven program for user interaction.

System Requirements:
• Language: Python 3.x
• Libraries: collections (for deque)
• Environment: Any Python IDE or CLI

Modules / Components:
• Graph Representation: Adjacency list using a Python dictionary.
• DFS Traversal: To test reachability.
• BFS Traversal: To determine the shortest path.
• User Interface: Console-based menu for user interaction.

Algorithm Design:
• DFS (Depth-First Search):
1. Initialize an empty visited set.
93
2. Start from the source node.
3. Recursively visit unvisited neighbors.
4. Stop if the target is found.

• BFS (Breadth-First Search):


1. Initialize a queue with the source node.
2. While the queue is not empty:
▪ Dequeue the front path.
▪ Check if the last node is the target.
▪ If not, enqueue paths with unvisited neighbors.

Python code:
from collections import deque

# Graph - peer connections


graph = {
'A': ['B', 'D'],
'B': ['A', 'C', 'E'],
'C': ['B'],
'D': ['A', 'E'],
'E': ['B', 'D', 'F'],
'F': ['E']
}

# BFS for shortest path


def bfs_shortest_path(graph, start, goal):
visited = set()
queue = deque([[start]])

if start == goal:
return [start]

while queue:
path = queue.popleft()
node = path[-1]
if node not in visited:
for neighbor in graph[node]:
new_path = list(path)
new_path.append(neighbor)
queue.append(new_path)
if neighbor == goal:

94
return new_path
visited.add(node)
return None

# DFS to check connection


def dfs(graph, node, target, visited=None):
if visited is None:
visited = set()
if node == target:
return True
if node not in visited:
visited.add(node)
for neighbor in graph[node]:
if dfs(graph, neighbor, target, visited):
return True
return False

# Menu
if name == " main ":
while True:
print("\n--- Peer-to-Peer Communication ---")
print("1. Check if peer is reachable (DFS)")
print("2. Find shortest path between peers (BFS)")
print("3. Exit")
choice = input("Enter choice: ")

if choice == '1':
src = input("Enter source peer: ").upper()
dest = input("Enter destination peer: ").upper()
reachable = dfs(graph, src, dest)
print("Reachable!" if reachable else "Not reachable.")

elif choice == '2':


src = input("Enter source peer: ").upper()
dest = input("Enter destination peer: ").upper()
path = bfs_shortest_path(graph, src, dest)
if path:
print("Shortest Path:", " -> ".join(path))
else:
print("No path found.")
95
elif choice == '3':
print("Exiting...")
break
else:
print("Invalid choice.")

output:

Result:
Thus, a peer-to-peer communication system was successfully simulated using
Python graphs. BFS and DFS were used to explore connectivity and communication
paths between peers.
96
Ex.No:14b Design of a Web Link Analyzer Using PageRank Algorithm
Date:

Aim
To design and implement a Python program that uses the PageRank algorithm to
evaluate and rank the importance of web pages based on their interlinking structure.

Objectives
• Model web pages as nodes and hyperlinks as directed edges in a graph.
• Apply the PageRank algorithm to rank the pages.
• Visualize the graph using NetworkX and Matplotlib.
• Provide meaningful interpretation of web connectivity.

Tools & Technologies


• Python 3.x
• NetworkX – for graph modeling and PageRank calculation
• Matplotlib – for data visualization

Problem Statement
Search engines rely on algorithms like PageRank to determine which web pages
are most relevant. This project simulates a simplified version of that logic to analyze and
rank web pages based on their interconnected structure.

Methodology
1. Represent web pages as a directed graph.
2. Define edges based on the links between web pages.
3. Use NetworkX’s pagerank() function to compute the ranks.
4. Visualize the web graph and annotate each node with its score.

Python Code Implementation


import networkx as nx
import matplotlib.pyplot as plt

# Step 1: Create a directed graph


G = nx.DiGraph()

# Step 2: Define hyperlinks between pages (edges)


edges = [
("Home", "About"),
("Home", "Products"),
("Products", "Home"),
("About", "Contact"),
("Contact", "Home"),
("Blog", "Home"),
("Blog", "Products"),
("Products", "Blog")
97
]

G.add_edges_from(edges)

# Step 3: Apply PageRank algorithm


page_ranks = nx.pagerank(G, alpha=0.85)

# Step 4: Display scores


print("PageRank Scores:")
for page, score in page_ranks.items():
print(f"{page}: {score:.4f}")

# Step 5: Visualize the web graph


plt.figure(figsize=(10, 6))
pos = nx.spring_layout(G, seed=42)
nx.draw(G, pos, with_labels=True, node_size=3000, node_color='skyblue', arrows=True,
font_weight='bold')

# Draw scores on the nodes


labels = {node: f"{node}\n({page_ranks[node]:.2f})" for node in G.nodes()}
nx.draw_networkx_labels(G, pos, labels=labels)

plt.title("Web Link Structure with PageRank Scores")


plt.show()

Output

Result

The program successfully computes the importance of each web page and displays
a visual representation of their connections and rankings using Page Rank.

98
Open Ended Experiment

Ex. No: 15 Develop a Python-based application to simulate a hierarchical file system


Date: and classify large documents using tree-based structures.

Problem Statement 1:

Design a data structure in Python to simulate a hierarchical file system for an


operating system environment.
Answer:
A tree data structure is ideal for simulating a hierarchical file system. In this model,
each node represents either a file or a folder. Each node includes attributes such as:

• name: The name of the file or folder


• type: To distinguish between a file and a folder
• children: A list of child nodes (applicable only for folders)

This structure naturally supports parent-child relationships, enabling recursive operations


like creation, deletion, navigation (cd), and listing (ls). It also provides an extensible
foundation for additional features such as file metadata, permissions, and search
functionality.

Problem Statement 2:

In a document classification system, how can tree structures help in organizing large
numbers of documents?

Answer:
Tree structures allow classification of documents into nested categories and
subcategories. Each internal node can represent a topic, and leaf nodes can represent
documents. It provides efficient insertion, search, and hierarchical browsing.

Problem Statement 3:

How would you implement a cd (change directory) and ls (list directory) command in a
tree-based file system simulation?

Answer:
Maintain a pointer to the current directory (node). For cd, traverse the child nodes
to match the folder name and update the pointer. For ls, print the names of all children of
the current node.

99
Problem Statement 4:

What is the advantage of using a tree over a flat list to store file or category structures?

Answer:
A tree supports nested hierarchies, enabling parent-child relationships, efficient
recursive traversal, and better organization of complex data. A flat list cannot represent
nested folders or categories properly.

Problem Statement 5:

How can you extend a tree-based file system to support file sizes and total folder size
calculation?

Answer:
Add a size attribute to each file node. For folders, recursively sum the sizes of all
child nodes to compute the total folder size. This allows dynamic tracking of storage usage.

100

You might also like