6.DS Student LAB MANUAL (Updated)
6.DS Student LAB MANUAL (Updated)
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 = []
print('Initial stack:')
print(stack)
Queue:
queue = []
# Enqueue elements
queue.append('a')
1
queue.append('b')
queue.append('c')
List = [1, 2, 3, 4]
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)
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
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]
if choice == '1':
n = int(input("Enter a number to calculate factorial: "))
print(f"Factorial of {n} is {factorial(n)}")
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
self.data[index] = value
self.size += 1
print(f"Inserted {value} at position {index}.")
self.data[self.size - 1] = None
self.size -= 1
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()
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")
if choice == '1':
value = input("Enter value to insert: ")
index = int(input("Enter position to insert (0-based index): "))
lst.insert(index, value)
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
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 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")
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 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 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")
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
if pos == 0:
self.insert_at_beginning(data)
return
temp = self.head
index = 0
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
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 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")
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 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}")
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 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)
if choice == '1':
item = input("Enter item to enqueue: ")
queue.enqueue(item)
37
print(f"{item} added to queue.")
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:
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
# Convert to lowercase
text_lower = text.lower()
# Remove punctuation
text_clean = text_lower.translate(str.maketrans('', '', string.punctuation))
# 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
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")
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}
while self.stack:
self.postfix.append(self.stack.pop())
return ''.join(self.postfix)
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]
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:]
i=j=k=0
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
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
if arr[mid] == target:
return mid # Target found, return index
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
# 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 display(self):
for i, bucket in enumerate(self.table):
print(f"Index {i}: {bucket}")
while True:
print("\nMenu:")
print("1. Insert")
print("2. Search")
print("3. Delete")
print("4. Display")
print("5. Exit")
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!")
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 display(self):
print("Tree as array:")
for i, val in enumerate(self.tree):
if val is not None:
print(f"Index {i}: {val}")
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:
Python Program:
# Node class
class Node:
def init (self, data):
self.data = data
self.left = None
self.right = None
# 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("\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()
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
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)
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
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
# 2. Update height
root.height = 1 + max(self.get_height(root.left), self.get_height(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:
Python Program:
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 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:
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)
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:
Algorithm:
• 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.
Python Program:
class DisjointSet:
def init (self, vertices):
self.parent = {v: v for v in vertices}
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:
Algorithm:
• 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.
81
Python program
import heapq
def prim(graph, start):
visited = set()
mst = []
total_cost = 0
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))
for v in vertices:
graph[v] = []
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
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:
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
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
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
#
while True:
print("\n1. Allocate Memory")
print("2. Free Memory")
print("3. Show Memory")
print("4. Exit")
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()
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)
# Convert to tensors
x = torch.tensor(features, dtype=torch.float)
edge_index = torch.tensor(edge_list, dtype=torch.long).t().contiguous()
# 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
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.
Python code:
from collections import deque
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
# 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.")
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.
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.
G.add_edges_from(edges)
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
Problem Statement 1:
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