The document outlines a laboratory manual for a Data Structures Design course, detailing objectives such as implementing abstract data types (ADTs) in Python and designing linear data structures. It includes a list of experiments covering various data structures and algorithms, including linked lists, stacks, queues, trees, and graphs. The course aims to equip students with practical skills in implementing and analyzing these data structures through hands-on programming assignments.
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 ratings0% found this document useful (0 votes)
4 views34 pages
Data Observation
The document outlines a laboratory manual for a Data Structures Design course, detailing objectives such as implementing abstract data types (ADTs) in Python and designing linear data structures. It includes a list of experiments covering various data structures and algorithms, including linked lists, stacks, queues, trees, and graphs. The course aims to equip students with practical skills in implementing and analyzing these data structures through hands-on programming assignments.
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/ 34
DEPARTMENT OF ARTIFICIAL
INTELLIGENCE AND DATA SCIENCE
AD3271- DATA STRUCTURES DESIGN LAB MANUAL REGULATION-2021 AD3271-DATA STRUCTURES DESIGN LABORATORY L T P C 0 0 4 2 COURSE OBJECTIVES: To implement ADTs in Python To design and implement linear data structures – lists, stacks, and queues To implement sorting, searching, and hashing algorithms To solve problems using tree and graph structures LIST OF EXPERIMENTS: Note: The lab instructor is expected to design problems based on the topics listed. The Examination shall no Implement simple ADTs as Python classes Implement recursive algorithms in Python Implement List ADT using Python arrays Linked list implementations of List Implementation of Stack and Queue ADTs Applications of List, Stack and Queue ADTs Implementation of sorting and searching algorithms Implementation of Hash tables Tree representation and traversal algorithms Implementation of Binary Search Trees Implementation of Heaps Graph representation and Traversal algorithms Implementation of single source shortest path algorithm Implementation of minimum spanning tree algorithms COURSE OUTCOMES: At the end of the course, the student should be able to: CO1: implement ADTs as Python classes CO2:design, implement, and analyse linear data structures, such as lists, queues, and stacks, according to t CO3:design, implement, and analyse efficient tree structures to meet requirements such as searching, index CO4: model problems as graph problems and implement efficient graph algorithms to solve them TOTAL:60 PERIODS EX.NO:1 ■ ■ IMPLEMENT SIMPLE ADTs as PYTHON CLASSES AIM: To write a python program to append, delete, and display the elements of a list class ALGORITHM: Step 1: Create a class check and using a construction initialize the value of a class Step2: Create the methods add (), remove () and display () of the list Step3:Create an object for the check class Step4: Using the object call the respective method depending upon the choice taken from the user Step5:pri PROGRAM: class check: def __init__(self): self.n = [] def add(self, a): self.n.append(a) def remove(self, b): if b in self.n: self.n.remove(b) else: print(f"{b} not found in the list.") def dis(self): return self.n obj1 = check() choice = 1 while choice != 0: print("0. Exit") print("1. Add") print("2. Delete") print("3. Display") choice = int(input("Enter the choice: ")) if choice == 1: n = int(input("Enter number to append: ")) obj1.add(n) print("List:", obj1.dis()) elif choice == 2: n = int(input("Enter number to delete: ")) obj1.remove(n) print("List:", obj1.dis()) elif choice == 3: print("List:", obj1.dis()) elif choice == 0: print("Exiting...") else: print("Invalid choice, try again!") print() OUTPUT: Exit Add Delete display Enter the choice 1 Enter number to append 23 List [23] Exit Add Delete display Enter the choice 1 Enter number to append 45 List [23, 45] Exit Add Delete display Enter the choice 1 Enter number to append 56 List [23, 45, 56] Exit Add Delete Display Enter the choice 3 List [23, 45, 56] Exit Add Delete Display Enter the choice 2 Enter number to remove 45 List [23, 56] Exit Add Delete Display Enter the choice 3 List [23, 56] Exit Add Delete Display Enter the choice 0 Exit RESULT: Thus, the implementation of concept of simple ADTs as python classes is executed and verified successfully EX.NO:2(a) ■ ■IMPLEMENT RECURSIVE ALGORTHMS IN PYTHON AIM: To write a python program to find the factorial of number using recursive function ALGORITHM: Step 1: Program description:compute factorial of n using recursive function Step 2: Input: non-negative numbers Step 3: Output: factorial of n Step 4: If(n==0): Step 5: Return 1 Step 6: Else: Step 7: return[n*(n-1)] PROGRAM: def factorial(n): if(n<=1): return 1 else: return(n*factorial(n-1)) n=int (input ("Enter number")) print("Factorial") print(factorial(n)) OUTPUT: Enter number 5 Factorial 120 RESULT: Thus, the implementation of recursive algorithm of factorial program is executed and verified successfully. EX.NO2 (b) IMPLEMENTATION OF RECURSIVE ALGORITHM (FIBONACCI SERIES) AIM: To write a python program to find the Fibonacci series of number ALGORITHM: Step 1: Problem description: computenth number using Fibonacci series Step 2: Input: non -negative numbers Step 3: Output: Fibonacci series of n Step 4: If(n==0): Step 5: Return 0 Step 6: Elif(n==0) or (n==2) Step 7:Return 1 Step 8:Else: Step 9:Return(fib(n-1)+fib(n-2)) PROGRAM: def recur_fibo(n): if n <= 1: return n else: return(recur_fibo(n-1) + recur_fibo(n-2)) nterms = int (input ("How many terms? ")) if nterms <= 0: print ("Please enter a positive integer") else: print ("Fibonacci sequence:") for i in range(nterms): print(recur_fibo(i)) OUTPUT: How many terms? 10 Fibonacci sequence: 0 1 1 2 3 5 8 13 21 34 RESULT: Thus, the implementation of recursive algorithm using Fibonacci series is executed and verified successfully EX.NO:3 ■IMPLEMENT LIST ADT USING PYTHON ARRAY AIM: To write a implement list ADT’s using python array. ALGORITHM: Step1: Firstly, define and declare an array and print the array Step2: By using index, print the particular element from array Step3: Create new array “brands” and print the array Step4:Using len(brands) we can find the length of array Step5: By using append we can add the elements at last in array Step6: To remove an element we can use del (), remove (), pop () methods Step7: Create another array “fruits”.in this we modify the elements using index Step8: To concatenate two arrays, we can use” +” operator Step9: to repeat an element, we can use “*” operator Step10:to slice an array, we can use [start: stop] PROGRAM: import array arr=array.array('i',[1,2,3]) print("The new created array is ",end="") for i in range(0,3): print(arr[i],end="") print("\t") arr.append(4) print("The appended array is",end=””) for i in range(0,4): print(arr[i],"\t",end="") print("\t") arr.insert(2,5) print("The array after insertion is ",end="") for i in range(0,5): print(arr[i],"\t",end="") OUTPUT: The new created array is: 1 2 3 The appended array is: 1 2 3 4 The array after insertion is: 1 2 5 3 4 RESULT: Thus, the expected results have executed and verified successfully. EX.NO:4(a) ■IMPLEMENTATION OF LINKED LIST (SINGLY LISTED LIST) AIM: To write a program about implementation of singlylinked list ALGORITHM: Step1: create a class node which has attributes .data &next is a pointer to the next node in the list Step2: create another class singly list it has a attributes head Step3: add node () will be able to a new node to the list create a new node it first checks, whether the head is none which means the list is empty it the list is not empty, then the new node will be added to end of the list if the list is empty, assign head will point to the new node now we are inserting the node at intermediate we are having two attributes prev, temp. The prev node point Step4: display () will display the nodes presents to the list transverse through the list till current point to null display each node by making current to point to node next PROGRAM: class Node: def __init__(self, data): self.data = data self.next = None class SinglyLinkedList: def __init__(self): self.head = None def display(self): temp = self.head if self.head is None: print("Empty list") return while temp is not None: print(temp.data, end=" ") # Added space for correct formatting temp = temp.next print() def insert_at_beg(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 is not None: temp = temp.next temp.next = new_node def insert_at_intermediate(self, data, pos=3): new_node = Node(data) temp = self.head if temp is None: print("List is empty, cannot insert at intermediate position.") return for i in range(1, pos - 1): if temp.next is None: print("Position out of bounds") return temp = temp.next new_node.next = temp.next temp.next = new_node list1 = SinglyLinkedList() Node1 = Node(10) list1.head = Node1 Node2 = Node(20) Node1.next = Node2 Node3 = Node(30) Node2.next = Node3 Node4 = Node(40) Node3.next = Node4 print("Node Creation") list1.display() print() print("Node insert at begin") list1.insert_at_beg(5) list1.display() print() print("Node insert at end") list1.insert_at_end(50) list1.display() print() print("Node insert at intermediate") list1.insert_at_intermediate(15, 3) list1.display() OUTPUT: Node Creation 10 20 30 40 Node insert at begin 5 10 20 30 40 Node insert at end 5 10 20 30 40 50 Node insert at intermediate 5 10 15 20 30 40 50 RESULT: The expected output is achieved using singly linked list verified and successfully. EX.NO:4(b) ■IMPLEMENTATION OF LINKED LIST (DOUBLY LISTED LIST) AIM: To write a program about implementation of doubly linked list ALGORITHM: Step1: Create a class node which has attributes .data, prev and. next. Next is a pointer to the next node in th Step2: Create another class doubly list andit has a attributes head Step3: Add node () will add to a new node to the list Create a new node It first checks, whether the head is none which means the list is empty C)If The list is empty, assign head will point to the new node D)it the list is NOT empty ,then the new node will be added to end of the list E) now we are inserting the node at intermediate we are having two attributes prev, temp. The prev node poi Step4: display () will display the nodes presents to the list transverse through the list till current point to null display each node by making current to point to node next 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 display(self): temp = self.head if self.head is None: print("Empty list") return while temp is not None: print(temp.data, end=" ") # Added space for correct formatting temp = temp.next print() def insert_at_beg(self, data): new_node = Node(data) if self.head is None: self.head = new_node return new_node.next = self.head self.head.prev = new_node self.head = new_node def deletion(self): if self.head is None: print("List is empty, deletion not possible.") return temp = self.head self.head = temp.next if self.head is not None: self.head.prev = None temp.next = None list1 = DoublyLinkedList() node1 = Node(10) list1.head = node1 node2 = Node(20) node1.next = node2 node2.prev = node1 node3 = Node(30) node2.next = node3 node3.prev = node2 node4 = Node(40) node3.next = node4 node4.prev = node3 print("\nDoubly Linked List:") list1.display() list1.insert_at_beg(5) print("\nInsert at beginning:") list1.display() list1.deletion() print("\nDeletion:") list1.display() OUTPUT: Doubly Linked List: 10 20 30 40 Insert at beginning: 5 10 20 30 40 Deletion: 10 20 30 40 RESULT: The expected output is achieved using doubly linked list verified and successfully. EX.NO:4(c) ■IMPLEMENTATION OF LINKED LIST (CIRCULAR LISTED LIST) AIM: To write a program about implementation of doubly linked list ALGORITHM: Step1: create a class node which has attributes .data. Next is a pointer to the next node in the list Step2: create another class circular linked list and it has a attributes head Step3: add node () will add to a new node to the list Create a new node It first checks, whether the head and tail are none C)If the list is empty, assignhead and tail will point to the new node and new node, next=self. Head D)It the list is NOT empty, then the new node will point to the new node will be added to end of the list Self. Tail. next=new node Self. Tail=new node Self. Tail=self. Head PROGRAM: class Node: def __init__(self, data): self.data = data self.next = None class CreateList: def __init__(self): self.head = None self.tail = None def add(self, data): newNode = Node(data) if self.head is None: self.head = newNode self.tail = newNode newNode.next = self.head else: self.tail.next = newNode self.tail = newNode self.tail.next = self.head def display(self): if self.head is None: print("List is empty") return print("Nodes of the circular linked list:") current = self.head while True: print(current.data) # Printing each node in a new line current = current.next if current == self.head: break cl = CreateList() cl.add(1) cl.add(2) cl.add(3) cl.add(4) cl.display() OUTPUT: Nodes of the circular linked list: 1 2 3 4 RESULT: The expected output is achieved using circular linked list verified and successfully. EX.NO:5(a) IMPLEMENTATION OF STACK ADTs AIM: To write a implement simple abstract data type in python classes. ALGORITHM: Step1: Create a class in which define the function: __init__(), isempty(),push(),pop(), peak() abd size(). Step2: To perform the above function create s=Stack() Step3: If the list is empty, isempty() returns True and False. Step4: Using push(), we can append o= an element in list. Step5: By pop(), removing the last element from list. Step6: Using size(), we can find the size length of the list. PROGRAM: class Stack: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def push(self, item): self.items.append(item) def pop(self): return self.items.pop() def peek(self): return self.items[len(self.items) - 1] def size(self): return len(self.items) s = Stack() print(s.isEmpty()) s.push(4) s.push('dog') print(s.peek()) s.push(True) print(s.size()) print(s.isEmpty()) s.push(8.4) print(s.pop()) print(s.pop()) print(s.size()) OUTPUT: True dog 3 False 8.4 True 2 RESULT: Thus, the implement simple abstract data type in python executed successfully. Ex. No: 5(B) IMPLEMENTATION OF QUEUE ADTs AIM: To write a programimplemented simple abstract data type in python classes. ALGORITHM: Step 1: Create a class Queue in which define the function: __init__, isEmpty(), enqueue(), dequeue(), front() Step 2: To perform above operation create q=Queue() Step 3: If the list is empty ,isEmpty() returns True and else False. Step 4: Using enque(), we can append the element in list. Step 5: By deque(), we can pop the element. Step 6: Using fron() Step 7: By size(), we an find the length of the list. PROGRAM: class Queue: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): self.items.append(item) def dequeue(self): if not self.isEmpty(): return self.items.pop(0) # Removes from front (FIFO) return "Queue is empty" def front(self): if not self.isEmpty(): return self.items[0] # First inserted element (Front of Queue) return "Queue is empty" def size(self): return len(self.items) q = Queue() print("queue operation example") print(q.isEmpty()) q.enqueue("Python") print(q.front()) q.enqueue(3) print(q.size()) q.enqueue(False) print(q.dequeue()) q.enqueue(11.5) print(q.dequeue()) print(q.dequeue()) q.enqueue(True) print(q.dequeue()) print(q.size()) OUTPUT: queue operation example True Python 2 Python 3 False 11.5 1 RESULT: Thus, the implement simple abstract datatype in python executed successfully. Ex. No: 6(A) APPLICATION OF LIST ADTs AIM: To write a program for implementation of Polynomial ADT. ALGORITHM: Step 1: Create a sum array sum[] of size is equal tomaximum of m and n. Step 2: Copy A[] to sum[] Step 3: Traverse the array B[]and do following for every element B[i] Step 4: Every element B[i] Step 5: Sum[i]=sum[i]+B[i] Step 6: Return sum[i] PROGRAM: def add(A, B, m, n): size = max(m, n) sum_poly = [0 for i in range(size)] for i in range(m): sum_poly[i] = A[i] for i in range(n): sum_poly[i] += B[i] return sum_poly def printpoly(poly, n): for i in range(n): print(poly[i], end=" ") if i != 0: print("x^", i, end=" ") if i != n - 1: print("+", end=" ") print() if __name__ == '__main__': A = [5, 0, 10, 6] B = [1, 2, 4] m = len(A) n = len(B) print("First polynomial is:") printpoly(A, m) print("Second polynomial is:") printpoly(B, n) sum_poly = add(A, B, m, n) size = max(m, n) print("Sum polynomial is:") printpoly(sum_poly, size) OUTPUT: first polynomial is: 5 + 0 x^ 1 + 10 x^ 2 + 6 x^ 3 second polynomial is: 1 + 2 x^ 1 + 4 x^ 2 sum polynomial is: 6 + 2 x^ 1 + 14 x^ 2 + 6 x^ 3 RESULT: Thus, the python program for implementation of polynomial ADT has been executed and verified successfull EX.NO: 6 (B) ■ ■APPLICATIONS OF STACK ADTs AIM: To write a python program to check if expression is correctly. ALGORITHM: Step 1: Create a class Stack with instance variable items initialized to all empty lists. Step 2: Define method push, pop and ik-empty inside the class stack. Step 3: The method push appends data of items. Step 4: The method pop pops the first element in items. Step5: The Method pop is empty return True only it items is empty. Step 6: Prompt the user for all expression. Step 7: Iterate through the characters of the expression and push to the stack it all open parenthesis is enco PROGRAM: class Stack: def __init__(self): self.items = [] def is_empty(self): return self.items == [] def push(self, data): self.items.append(data) def pop(self): if not self.is_empty(): return self.items.pop() return None exp = input("Please enter the expression:\n") s = Stack() is_balanced = True for c in exp: if c == '(': s.push(1) elif c == ')': if s.is_empty(): is_balanced = False print("expression is not correctly parenthesized") else: s.pop() if not s.is_empty(): is_balanced = False print("expression is not correctly parenthesized") if not is_balanced: print("expression is not correctly parenthesized") OUTPUT: Please enter the expression: (a+b))(3) expression is not correctly parenthesized expression is not correctly parenthesized RESULT: Thus, the python program for implementation of whether expression is correctly parenthesized has been exe EX.NO:6(C) ■ ■ APPLICATIONS OF QUEUE ADTs AIM: To write a python program to create that creates a dequeue and allow the user to perform append and pop o ALGORITHM: Step 1: Create a class dequeue with instance variable item initialized to all empty list. Step 2: Define method appends, append-left-popmpops left and is empty inside the class dequeue. Step 3: The Method append appends data to item from the right. Step 4: The method append-left append data to items from the left. Step 5: The method pop pops from the right from items. Step 6: The method pop-left pops from the left from items. Step 7: The method is empty returns True only if items is empty. PROGRAM: class Dequeue: def __init__(self): self.items = [] def is_empty(self): return self.items == [] def append(self, data): self.items.append(data) def append_left(self, data): self.items.insert(0, data) def pop(self): if not self.is_empty(): return self.items.pop() return "Dequeue is empty" def pop_left(self): if not self.is_empty(): return self.items.pop(0) return "Dequeue is empty" q = Dequeue() print("Menu:") print("append <value>") print("append left <value>") print("pop") print("popleft") print("quit") while True: do = input("What would you like to do? ").strip().lower().split() if len(do) == 0: continue # Ignore empty input operation = do[0] if operation == 'append': if len(do) == 2: q.append(int(do[1])) elif operation == 'append' and do[1] == 'left': # Fix: Handle "append left" if len(do) == 3: q.append_left(int(do[2])) elif operation == 'pop': if q.is_empty(): print("Dequeue is empty") else: print("Popped value from right:", q.pop()) elif operation == 'popleft': if q.is_empty(): print("Dequeue is empty") else: print("Popped value from left:", q.pop_left()) elif operation == 'quit': break else: print("Invalid operation, please try again.") OUTPUT: Menu: append <value> append left <value> pop popleft quit What would you like to do? append 1 What would you like to do? append 2 What would you like to do? pop Popped value from right: 2 What would you like to do? pop Popped value from right: 1 What would you like to do? append left 1 What would you like to do? append left 2 What would you like to do? pop Popped value from right: 1 What would you like to do? pop Popped value from right: 2 RESULT: Thus, the python program for implementation of dequeues and allows the user to perform appends and pop Ex.No:7(A) IMPLEMENTATION OF SORTING AND SEARCHING ALGORITHMS MERGE SORT AIM: Write a python program to implement merge sort. ALGORITHM: STEP-1: First, check of the left index of array is less than the right index, if yes then calculate the midpoint. STEP-2: We see that an array of 6 items is divided into two arrays of size 3 and 3 respectively. STEP-3: Again find that is left index is less than right index for both arrays, if yes then again calculate mid po STEP-4: Further divide these two arrays into further halves, until the atomic unit of array is reached. STEP-5: Divide the array into smallest unit, start merging the elements based on comparison of size of elem STEP-6: Compare the element for each list and then combine them into another list in a sorted manner. STEP-7: Finally merge the list sorted. PROGRAM: def mergesort(list1): if len(list1) <= 1: return list1 mid = len(list1) // 2 left_list = mergesort(list1[:mid]) right_list = mergesort(list1[mid:]) return merge(left_list, right_list) def merge(left_list, right_list): sorted_list = [] i=j=0 while i < len(left_list) and j < len(right_list): if left_list[i] < right_list[j]: sorted_list.append(left_list[i]) i += 1 else: sorted_list.append(right_list[j]) j += 1 while i < len(left_list): sorted_list.append(left_list[i]) i += 1 while j < len(right_list): sorted_list.append(right_list[j]) j += 1 return sorted_list list1 = [23, 65, 76, 54, 32, 5] print("Sorted list:", mergesort(list1)) OUTPUT: [5, 23, 32, 54, 65, 76] RESULT: Thus, the implementation of concept of merge sort is executed and verified successfully. Ex.No:7 (B) QUICK SORTS AIM: To write a python program to implement the quick sort. ALGORITHM: STEP-1: Create a function partition() STEP-2: Pass three parameters arr, low, high. STEP-3: Select right most element as Pivot. STEP-4: Traverse through all elements and compare them with the Pivot. STEP-5: If the smaller element is found swap them with the Pivot. STEP-6: Return the index position. STEP-7: Create a function Quick Sort() STEP-8: Pass three parameters arr, low, high. STEP-9: Find the Pivot element. STEP-10: Do recursive call on the left Pivot and right Pivot. STEP-11: The array is now sorted. STEP-12: Print the sorted array. PROGRAM: def partition(arr, low, high): pivot = arr[high] i = low - 1 for j in range(low, high): if arr[j] < pivot: i += 1 arr[i], arr[j] = arr[j], arr[i] arr[i + 1], arr[high] = arr[high], arr[i + 1] return i + 1 def quick_sort(arr, low, high): if low < high: pi = partition(arr, low, high) quick_sort(arr, low, pi - 1) # Recursive call for left part quick_sort(arr, pi + 1, high) # Recursive call for right part arr = [23,65,76,54,32,5] n = len(arr) quick_sort(arr, 0, n - 1) print("Sorted array:", arr) RESULT: Thus, the implementation of concept of Quick Sort is executed and verified successfully. EX.NO:7(C ) LINEAR SEARCH AIM: To write a python program to implement the linear search. ALGORITHM: STEP-1: Start the program. STEP-2: Create a class as linear search. STEP-3: Initialize array elements and key value to be searched. STEP-4: Traverse the Whole array. STEP-5: Match the key element with array elements. STEP-6: If the key element is found, return the index position of the array elements. STEP-7: If the key element is not found return-1. STEP-8: Stop the program. PROGRAM: def linear_Search(list1, n, key): for i in range(0, n): if list1[i] == key: # Corrected from list[i] to list1[i] return i return -1 list1 = [1, 3, 5, 4, 7, 9] print("List:", list1) key = int(input("Enter the key to search: ")) n = len(list1) res = linear_Search(list1, n, key) if res == -1: print("Element not found") else: print("Element found at index:", res) RESULT: Thus, the implementation of concept of linear search is executed and verified successfully. Ex.No:7(D) BINARY SEARCH AIM: To write a python program to implement the linear search. ALGORITHM: STEP-1: Start the program. STEP-2: Create a class as Binary search. STEP-3: Define a method as Binary Search. STEP-3(a): Find the middle element by first +last/2. STEP-3(b): Compute the middle element with the key element to be searched. STEP-3(c): If the middle element greater than key element then only left half should be searched. STEP-3(d): Else right half should be searched. STEP-4: Call the method(Binary Search) STEP-5: Stop the program. PROGRAM: def binarySearchAppr(arr, start, end, x): if end >= start: mid = start + (end - start) // 2 if arr[mid] == x: return mid elif arr[mid] > x: return binarySearchAppr(arr, start, mid - 1, x) else: return binarySearchAppr(arr, mid + 1, end, x) else: return -1 arr = sorted(['t', 'u', 't', 'o', 'r', 'i', 'a', 'l']) x = 'r' result = binarySearchAppr(arr, 0, len(arr) - 1, x) if result != -1: print("Element is present at index " + str(result)) else: print("Element is not present in array") RESULT: Thus, the implementation of concept of Binary Search is executed and verified successfully. EX NO.8 IMPLEMENTATION OF HASH TABLE AIM: To write a python program to implement the concept of hashing using separate chaining. ALGORITHM: STEP-1: Create the table size 10. STEP-2: Create hash function. STEP-3: Find out the hash key using the formula keywords % len(hash table) STEP-4: Insert a node in the Hash table by using the corresponding hash key. STEP-5: Display the hash entry. PROGRAM: hashTable = [[] for _ in range(10)] def checkPrime(n): if n <= 1: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True def getPrime(n): if n % 2 == 0: n += 1 while not checkPrime(n): n += 2 return n def hashFunction(key): capacity = getPrime(10) return key % capacity def insertData(key, data): index = hashFunction(key) hashTable[index] = [key, data] # Replace instead of append def removeData(key): index = hashFunction(key) hashTable[index] = 0 # Overwrite with 0 insertData(123, "apple") insertData(432, "mango") insertData(213, "banana") insertData(654, "guava") print(hashTable) removeData(123) print(hashTable) OUTPUT: [[], [], [123, 'apple'], [432, 'mango'], [213, 'banana'], [654, 'guava'], [], [], [], []] [[], [], 0, [432, 'mango'], [213, 'banana'], [654, 'guava'], [], [], [], []] RESULT: Thus, the implementation of concept of hashing using separate chaining is verified and executed successfull EX.NO: 9 TREE REPRESENTATIONS AND TRAVERSAL ALGORITHM AIM: To write a python to implement the tree representation and Traversal Algorithm. ALGORITHM: Step1: The left subtree of a node contains smaller nodes than the root node. Step2: The right subtree of a node contains greater than the root the node. Step3: Three types of Traversals Preorder Traversal Algorithm Visit the root node Traverse the left subtree in Pre-order Traverse the right subtree in Pre-order In order Traversal Algorithm visit the left subtree in in order visit the root node visit the right subtree in inorder Postorder Traversal Algorithm Traverse the left subtree in Postorder Traverse the right subtree in Postorder PREORDER if (n! =null): print(n.data) preorder(n,left) preorder (n,right) INORDER if (n! =null): in order (n, left) print(n.data) inorder(right) POSTORDER if (n! =null): postorder(n, left) postorder(n,right) print(n.data) PROGRAM: i)INORDER class TreeNode: def __init__(self, val): self.val = val self.left = None self.right = None def inorderTraversal(root): answer = [] inorderTraversalUtil(root, answer) return answer def inorderTraversalUtil(root, answer): if root is None: return inorderTraversalUtil(root.left, answer) answer.append(root.val) inorderTraversalUtil(root.right, answer) root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) print(inorderTraversal(root)) OUTPUT: [4, 2, 5, 1, 3] ii)PREORDER: class TreeNode: def __init__(self, val): self.val = val self.left = None self.right = None def preorderTraversal(root): answer = [] preorderTraversalUtil(root, answer) return answer def preorderTraversalUtil(root, answer): if root is None: return answer.append(root.val) # Visit root first preorderTraversalUtil(root.left, answer) # Traverse left preorderTraversalUtil(root.right, answer) # Traverse right # Create Tree root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) # Print Preorder Traversal print(preorderTraversal(root)) OUTPUT: [1, 2, 4, 5, 3] iii)POSTORDER TRAVERSAL: class TreeNode: def __init__(self, val): self.val = val self.left = None self.right = None def postorderTraversal(root): answer = [] postorderTraversalUtil(root, answer) return answer def postorderTraversalUtil(root, answer): if root is None: return postorderTraversalUtil(root.left, answer) postorderTraversalUtil(root.right, answer) answer.append(root.val) root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) print(postorderTraversal(root)) OUTPUT: [4, 5, 2, 3, 1] RESULT: Thus, the implementation of tree representation and Traversal Algorithm is verified and executed successfull EX.NO:10 IMPLEMENTATION OF BINARY SEARCH TREES AIM: To write a python program creates a Binary search tree and presents a menu to the user to per. ALGORITHM: Step 1: Create a class Node with instance variables key,left,right and parent. Step 2: Define methods insert,inorder,min value Node and delete Node in binary search. Step 3: The method insert takes a node (or) argument and inserts the nodes in the BTS with node object as Step 4: The method inorder displays the inorder traversal of Binary search tree object as root. Step 5: The method minvalue node finds left most node in the Binary search tree with the Bst node object as Step 6: The method search takes a key (or) argument the returns the node with the key in the Binary search tree. PROGRAM: class Node: def __init__(self, key): self.key = key self.left = None self.right = None def inorder(root): if root is not None: inorder(root.left) # Traverse left print(str(root.key) + " ->", end=' ') # Print root inorder(root.right) # Traverse right def insert(node, key): if node is None: return Node(key) if key < node.key: node.left = insert(node.left, key) else: node.right = insert(node.right, key) return node def minValueNode(node): current = node while current.left is not None: current = current.left return current def deleteNode(root, key): if root is None: return root if key < root.key: root.left = deleteNode(root.left, key) elif key > root.key: root.right = deleteNode(root.right, key) else: if root.left is None: temp = root.right root = None return temp elif root.right is None: temp = root.left root = None return temp temp = minValueNode(root.right) root.key = temp.key # Replace node's key with successor's key root.right = deleteNode(root.right, temp.key) return root root = None root = insert(root, 8) root = insert(root, 3) root = insert(root, 1) root = insert(root, 6) root = insert(root, 7) root = insert(root, 10) root = insert(root, 14) root = insert(root, 4) print("Inorder traversal: ", end=' ') inorder(root) print("\nDelete 10") root = deleteNode(root, 10) print("Inorder traversal: ", end=' ') inorder(root) OUTPUT: Inorder traversal: 1-> 3-> 4-> 6-> 7-> 8-> 10-> 14-> Delete 10 Inorder traversal: 1-> 3-> 4-> 6-> 7-> 8-> 14-> EX.NO:11 IMPLEMENTATION OF HEAP AIM: To write a python program to implement the concept of heap sort. ALGORITHM: Step 1: Create a class Binary heap with instance variable items set to an empty list. This empty list is used to store the binary heap. Step 2: Define methods size, parent, left, right, get, get_max, extract_max, max_heapily, swap and insert. Step 3: The method size returns the number of elements in the heap. Step 4: The method parent takes an index as argument and returns the index of the parent. Step 5: The method left takes an indec as argument and returns the index of its left child. Step 6: The method right takes an index as argument and returns the index of its right child. Step 7: The method get takes an index as argument and returns the key at the index. Step 8: The method get_max returns the maximum element in the heap by returning the first element in list items. Step 9: The method extract_max returns the maximum element in the heap and removes it. Step 10: The method max_heapify takes an index as argument and modifies the heap structure at and below the node at this index to make it satisfy the heap property. Step 11: The method swap takes two indexes as arguments and swaps the corresponding element in the heap. Step 12: The method insert takes a key as argument and adds that key to the heap. PROGRAM: class BinaryHeap: def __init__(self): self.items = [] def size(self): return len(self.items) def parent(self, i): return (i - 1) // 2 def left(self, i): return 2 * i + 1 def right(self, i): return 2 * i + 2 def get(self, i): return self.items[i] def get_max(self): return self.items[0] if self.size() > 0 else None def extract_max(self): if self.size() == 0: return None largest = self.get_max() self.items[0] = self.items[-1] self.items.pop() self.max_heapify(0) return largest def max_heapify(self, i): l = self.left(i) r = self.right(i) largest = i if l < self.size() and self.get(l) > self.get(i): largest = l if r < self.size() and self.get(r) > self.get(largest): largest = r if largest != i: self.swap(largest, i) self.max_heapify(largest) def swap(self, i, j): self.items[i], self.items[j] = self.items[j], self.items[i] def insert(self, key): self.items.append(key) index = self.size() - 1 # Get index of newly inserted element while index > 0: p = self.parent(index) if self.get(p) < self.get(index): self.swap(p, index) index = p # Move up to the parent else: break # Heap property satisfied bheap = BinaryHeap() print('Menu:') print('insert <data>') print('max get') print('max extract') print('quit') while True: try: do = input('What would you like to do? ').strip().split() if not do: continue # Ignore empty input operation = do[0].lower() if operation == 'insert': if len(do) < 2 or not do[1].lstrip('-').isdigit(): print('Invalid input. Usage: insert <data>') continue data = int(do[1]) bheap.insert(data) elif operation == 'max': if len(do) < 2: print('Invalid input. Usage: max get | max extract') continue suboperation = do[1].lower() if suboperation == 'get': max_value = bheap.get_max() print('Maximum value:', max_value if max_value is not None else 'Heap is empty') elif suboperation == 'extract': max_value = bheap.extract_max() print('Maximum value removed:', max_value if max_value is not None else 'Heap is empty') else: print('Invalid input. Usage: max get | max extract') elif operation == 'quit': print('Exiting...') break else: print('Invalid command. Try again.') except Exception as e: print('Error:', e) OUTPUT: Case 1: Menu insert<data> max get max extract quit What would you like to do? insert 5 What would you like to do? insert 3 What would you like to do? insert -3 What would you like to do? insert 10 What would you like to do? insert 8 What would you like to do? max get Maximum value: 10 What would you like to do? max extract Maximum value removed: 10 What would you like to do? max extract Maximum value removed: 8 What would you like to do? max extract Maximum value removed: 5 What would you like to do? max extract Maximum value removed: 3 What would you like to do? max get Maximum value: -3 What would you like to do? quit Case 2: Menu insert<data> max get max extract quit What would you like to do? insert 3 What would you like to do? insert 11 What would you like to do? insert 5 What would you like to do? max extract Maximum value removed: 11 What would you like to do? max get Maximum value: 5 What would you like to do? max extract Maximum value removed: 5 What would you like to do? insert 15 What would you like to do? max get Maximum value: 15 What would you like to do? quit RESULT: Thus, the implementation of concept of Heapsort is executed and verified successfully. EX.NO: 12(a) GRAPH REPRESENTATION AND TRAVERSAL ALGORITHMS AIM: Write a python program to implement graph representation and Traversal Algorithm. FOR BREADTH FIRST SEARCH: ALGORITHM: Step 1: Start by putting any one of the graphs vertices at the back of queue. Step 2: Now take the front item of the queue and add it to the visited list. Step 3: Create a list of that vertex's adjacent nodes add those which are not within the visited list to the rear of the queue. Step 4: Keep containing steps two and three fill the queue is Empty. PROGRAM: from collections import defaultdict class Graph: def __init__(self): self.graph = defaultdict(list) def addEdge(self, u, v): self.graph[u].append(v) def BFS(self, s): visited = [False] * (max(self.graph.keys()) + 1) queue = [] queue.append(s) visited[s] = True while queue: s = queue.pop(0) print(s, end=" ") for i in self.graph[s]: if not visited[i]: queue.append(i) visited[i] = True g = Graph() g.addEdge(0, 1) g.addEdge(0, 2) g.addEdge(1, 2) g.addEdge(2, 0) g.addEdge(2, 3) g.addEdge(3, 3) print("Following is Breadth First Traversal (starting from vertex 2):") g.BFS(2) OUTPUT: Following is Breadth First Traversal (starting from vertex 2): 2031 DEPTH FIRST SEARCH: ALGORITHM: Step 1: Depth-first search is an algorithm for traversing or searching tree or graph data structures. The Algorithm starts at the root nodes (Selecting some arbitrary node as the root node in the case of graph) and explores as for as possible along each branch before backtracking. Step 2: Create a recursive function takes the index of the node and a visited array. Step 3: Mark current node as visited and print the node. Step 4: Traverse all the adjacent and unmarked nodes and call the recursive function with index of the adjacent node. PROGRAM: from collections import defaultdict class Graph: def __init__(self): self.graph = defaultdict(list) def addEdge(self, u, v): self.graph[u].append(v) def DFSUtil(self, v, visited): visited.add(v) print(v, end=" ") for neighbour in self.graph[v]: if neighbour not in visited: self.DFSUtil(neighbour, visited) def DFS(self): visited = set() for vertex in self.graph: if vertex not in visited: self.DFSUtil(vertex, visited) if __name__ == "__main__": print("Following is Depth First Traversal:") g = Graph() g.addEdge(0, 1) g.addEdge(0, 2) g.addEdge(1, 2) g.addEdge(2, 0) g.addEdge(2, 3) g.addEdge(3, 3) g.DFS() OUTPUT: Following is Depth First Traversal: 0123 RESULT: Thus, the implementation of graph representation and Traversal Algorithm is verified and executed successfully. EX. NO: 13 IMPLEMENTATION OF SINGLE SOURCE SHORTEST PATH ALGORITHM AIM: Write a python program to implement the single shortest path algorithm. ALGORITHM: STEP-1: Create classes for graph and vertex. STEP-2: Create a function dijkstra that takes a graph object and a source vertex as arguments. STEP-3: The function begins by creating a set unvisited and adding all the vertices in the graph to it. STEP-4: A dictionary distance is created with keys as the vertices in the graph and their value all set to infinity. STEP-5: Distance[source] is set to 0. STEP-6: The algorithm proceeds by finding the vertex that has the minimum distance in the set unvisited. STEP-7: It then removes this vertex from the set unvisited. STEP-8: Then all the neighbours of this vertex that have not been visited yet have their distances. STEP-9: The above steps repeat until the set unvisited. STEP-10: The dictionary distance is returned. STEP-11: This algorithm works for both undirected and graph. PROGRAM: from collections import defaultdict class Graph: def __init__(self): self.vertices = {} def add_vertex(self, key): vertex = Vertex(key) self.vertices[key] = vertex def get_vertex(self, key): return self.vertices.get(key, None) def __contains__(self, key): return key in self.vertices def add_edge(self, src_key, dest_key, weight=1): if src_key in self.vertices and dest_key in self.vertices: self.vertices[src_key].add_neighbour(self.vertices[dest_key], weight) def does_edge_exist(self, src_key, dest_key): return self.vertices[src_key].does_it_point_to(self.vertices[dest_key]) def __iter__(self): return iter(self.vertices.values()) class Vertex: def __init__(self, key): self.key = key self.points_to = {} def get_key(self): return self.key def add_neighbour(self, dest, weight): self.points_to[dest] = weight def get_neighbours(self): return self.points_to.keys() def get_weight(self, dest): return self.points_to.get(dest, float('inf')) def does_it_point_to(self, dest): return dest in self.points_to def dijkstra(g, source): unvisited = set(g.vertices.values()) distance = {vertex: float('inf') for vertex in g.vertices.values()} distance[source] = 0 while unvisited: closest = min(unvisited, key=lambda v: distance[v]) unvisited.remove(closest) for neighbour in closest.get_neighbours(): if neighbour in unvisited: new_distance = distance[closest] + closest.get_weight(neighbour) if distance[neighbour] > new_distance: distance[neighbour] = new_distance return distance g = Graph() print('Undirected Graph') print('Menu') print('add vertex <key>') print('add edge <src> <dest> <weight>') print('shortest <source vertex key>') print('display') print('quit') while True: do = input('What would you like to do? ').split() operation = do[0] if operation == 'add': suboperation = do[1] if suboperation == 'vertex': key = int(do[2]) if key not in g: g.add_vertex(key) else: print('Vertex already exists.') elif suboperation == 'edge': src = int(do[2]) dest = int(do[3]) weight = int(do[4]) if src not in g: print(f'Vertex {src} does not exist.') elif dest not in g: print(f'Vertex {dest} does not exist.') else: if not g.does_edge_exist(src, dest): g.add_edge(src, dest, weight) g.add_edge(dest, src, weight) else: print('Edge already exists.') elif operation == 'shortest': key = int(do[1]) source = g.get_vertex(key) if source: distance = dijkstra(g, source) print(f'Distances from {key}:') for v in distance: print(f'Distance to {v.get_key()}: {distance[v]}') print() else: print(f'Vertex {key} does not exist.') elif operation == 'display': print('Vertices:', end=' ') for v in g: print(v.get_key(), end=' ') print() print('Edges:') for v in g: for dest in v.get_neighbours(): w = v.get_weight(dest) print(f'(src={v.get_key()}, dest={dest.get_key()}, weight={w})') elif operation == 'quit': break OUTPUT: Case 1: Undirected Graph Menu add vertex <key> add edge <src><dest><weight> shortest <source vertex key> display quit What would you like to do? add vertex 1 What would you like to do? add vertex 2 What would you like to do? add vertex 3 What would you like to do? add vertex 4 What would you like to do? add vertex 5 What would you like to do? add vertex 6 What would you like to do? add vertex 7 What would you like to do? add edge 1 2 10 What would you like to do? add edge 1 3 80 What would you like to do? add edge 3 4 70 What would you like to do? add edge 2 5 20 What would you like to do? add edge 2 3 6 What would you like to do? add edge 5 6 50 What would you like to do? add edge 5 7 10 What would you like to do? add edge 6 7 5 What would you like to do? shortest 1 Distances from 1: Distance to 6: 45 Distance to 3: 16 Distance to 4: 86 Distance to 5: 30 Distance to 2: 10 Distance to 7: 40 Distance to 1: 0 What would you like to do? quit Case 2: Undirected Graph Menu add vertex <key> add edge <src><dest><weight> shortest <source vertex key> display quit What would you like to do? add vertex 1 What would you like to do? add vertex 2 What would you like to do? add vertex 3 What would you like to do? add vertex 4 What would you like to do? add edge 1 2 10 What would you like to do? add edge 2 3 20 What would you like to do? add edge 3 4 30 What would you like to do? add edge 1 4 100 What would you like to do? shortest 1 Distances from 1: Distance to 2: 10 Distance to 4: 60 Distance to 3: 30 Distance to 1: 0 RESULT: Thus, the implementation of single source shortest path algorithm is verified andexecuted successfully. EX. NO:14 IMPLEMENTATION OF MINIMUM SPANNING TREE ALGORITHM AIM: Write a program to implement the concept of minimum spanning tree. ALGORITHM: STEP-1: Create classes for graph and vertex. Create a function mst_krusal that takes a graph object g as argument. STEP-2: The function will return a graph object which will hold a MST of the graph g. STEP-3: The empty graph called mst is created which is a minimum spanning tree of the graph g. STEP-4: An Empty graph called mst is created which hold g. STEP-5: The algorithm works by first sorting weight. STEP-6: Then the smallest edge is taken from the sorted list. STEP-7: If that edge does not form a cycle when added it. STEP-8: Them the next smallest edge is taken and step 7 again. STEP-9: The above is performed until mst has the same as g. STEP-10: To determine whether adding an edge cycle. STEP-11: If both vertices of an edge belong to the component then adding edge will form a cycle. PROGRAM: class Graph: def __init__(self): self.vertices = {} def add_vertex(self, key): vertex = Vertex(key) self.vertices[key] = vertex def get_vertex(self, key): return self.vertices.get(key, None) def __contains__(self, key): return key in self.vertices def add_edge(self, src_key, dest_key, weight=1): if src_key in self.vertices and dest_key in self.vertices: self.vertices[src_key].add_neighbour(self.vertices[dest_key], weight) def does_vertex_exist(self, key): return key in self.vertices def does_edge_exist(self, src_key, dest_key): return self.vertices[src_key].does_it_point_to(self.vertices[dest_key]) def display(self): print('Vertices:', end=' ') for v in self: print(v.get_key(), end=' ') print() print('Edges:') for v in self: for dest in v.get_neighbours(): w = v.get_weight(dest) print(f'(src={v.get_key()}, dest={dest.get_key()}, weight={w})') def __len__(self): return len(self.vertices) def __iter__(self): return iter(self.vertices.values()) class Vertex: def __init__(self, key): self.key = key self.points_to = {} def get_key(self): return self.key def add_neighbour(self, dest, weight): self.points_to[dest] = weight def get_neighbours(self): return self.points_to.keys() def get_weight(self, dest): return self.points_to.get(dest, float('inf')) def does_it_point_to(self, dest): return dest in self.points_to def mst_kruskal(g): mst = Graph() if len(g) == 1: u = next(iter(g)) mst.add_vertex(u.get_key()) return mst edges = [] for v in g: for n in v.get_neighbours(): if v.get_key() < n.get_key(): edges.append((v, n, v.get_weight(n))) edges.sort(key=lambda edge: edge[2]) component = {v: i for i, v in enumerate(g)} edge_index = 0 while len(mst) < len(g): u, v, weight = edges[edge_index] edge_index += 1 if component[u] != component[v]: if not mst.does_vertex_exist(u.get_key()): mst.add_vertex(u.get_key()) if not mst.does_vertex_exist(v.get_key()): mst.add_vertex(v.get_key()) mst.add_edge(u.get_key(), v.get_key(), weight) mst.add_edge(v.get_key(), u.get_key(), weight) old_component = component[v] new_component = component[u] for w in g: if component[w] == old_component: component[w] = new_component return mst g = Graph() print('Undirected Graph') print('Menu') print('add vertex <key>') print('add edge <src> <dest> <weight>') print('mst') print('display') print('quit') while True: do = input('What would you like to do? ').split() operation = do[0] if operation == 'add': suboperation = do[1] if suboperation == 'vertex': key = int(do[2]) if key not in g: g.add_vertex(key) else: print('Vertex already exists.') elif suboperation == 'edge': src = int(do[2]) dest = int(do[3]) weight = int(do[4]) if src not in g: print(f'Vertex {src} does not exist.') elif dest not in g: print(f'Vertex {dest} does not exist.') else: if not g.does_edge_exist(src, dest): g.add_edge(src, dest, weight) g.add_edge(dest, src, weight) else: print('Edge already exists.') elif operation == 'mst': mst = mst_kruskal(g) print('Minimum Spanning Tree:') mst.display() print() elif operation == 'display': g.display() print() elif operation == 'quit': break OUTPUT: Case 1: Undirected Graph Menu add vertex <key> add edge <src><dest><weight> mst display quit What would you like to do? add vertex 1 What would you like to do? add vertex 2 What would you like to do? add vertex 3 What would you like to do? add vertex 4 What would you like to do? add vertex 5 What would you like to do? add vertex 6 What would you like to do? add edge 1 2 10 What would you like to do? add edge 1 5 30 What would you like to do? add edge 1 4 40 What would you like to do? add edge 2 5 20 What would you like to do? add edge 4 5 40 What would you like to do? add edge 5 3 40 What would you like to do? add edge 5 6 70 What would you like to do? add edge 3 6 50 What would you like to do? mst Minimum Spanning Tree: Vertices: 1 2 3 4 5 6 Edges: (src=1, dest=4, weight=40) (src=1, dest=2, weight=10) (src=2, dest=5, weight=20) (src=2, dest=1, weight=10) (src=3, dest=5, weight=40) (src=3, dest=6, weight=50) (src=4, dest=1, weight=40) (src=5, dest=2, weight=20) (src=5, dest=3, weight=40) (src=6, dest=3, weight=50) What would you like to do? quit Case 2: Undirected Graph Menu add vertex <key> add edge <src><dest><weight> mst display quit What would you like to do? add vertex 1 What would you like to do? add vertex 2 What would you like to do? add vertex 3 What would you like to do? add edge 1 2 10 What would you like to do? add edge 1 3 20 What would you like to do? add edge 2 3 30 What would you like to do? mst Minimum Spanning Tree: Vertices: 1 2 3 Edges: (src=1, dest=3, weight=20) (src=1, dest=2, weight=10) (src=2, dest=1, weight=10) (src=3, dest=1, weight=20) What would you like to do? Quit RESULT: Thus, the implementation of minimum spacing tree algorithm is verified and executed successfully.