ADS Programs Using Python
ADS Programs Using Python
Ex.No: 1
IMPLEMENTATION OF FIBONACCI NUMBER
USING RECURSION
PROGRAM:
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
# Example usage
n = int(input("Enter the value of n for Fibonacci series: "))
result = fibonacci(n)
print(f"The {n}th Fibonacci number is: {result}")
OUTPUT
Enter the value of n for Fibonacci series: 8
The 8th Fibonacci number is: 21
RESULT:
Thus the python program to implement Fibonacci number using Recursion was
written,
executed and Verified successfully.
AIM:
To write a python program to implement Fibonacci number using Iteration.
ALGORITHM:
● The Node class represents a node in the binary tree.
● The preorder function performs a preorder traversal of the binary tree and
prints the data of each node.
Ex.No: 2
IMPLEMENTATION OF FIBONACCI NUMBER
USING ITERATION
PROGRAM:
class Node:
def __init__(self, key):
self.data = key
self.left = self.right = None
def preorder(root):
if root is not None:
print(root.data, end=" ")
preorder(root.left)
preorder(root.right)
# Example usage
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.right.left = Node(5)
root.right.right = Node(6)
root.right.left.left = Node(7)
root.right.left.right = Node(8)
print("Preorder Traversal:")
preorder(root)
5
OUTPUT
Preorder Traversal:
12435786
RESULT:
Thus the python program to implement Fibonacci number using Recursion was
written,
executed and Verified successfully.
AIM:
To write a python program to implement merge sort analysis.
ALGORITHM:
● The merge_sort function recursively divides the array into halves until it
contains only one element.
● The merge function is responsible for merging two sorted halves into a single
sorted array.
PROGRAM:
Ex.No: 3a
IMPLEMENTATION OF MERGE SORT
ANALYSIS
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2 # Calculate the middle index
# Divide the array into two halves
left_half = arr[:mid]
right_half = arr[mid:]
# Recursive calls to sort each half
merge_sort(left_half)
merge_sort(right_half)
# Merge the sorted halves
merge(arr, left_half, right_half)
def merge(arr, left, right):
i=j=k=0
# Compare elements from left and right halves and merge in sorted order
while i < len(left) and j < len(right):
if left[i] < right[j]:
arr[k] = left[i]
i += 1
else:
arr[k] = right[j]
j += 1
k += 1
# Copy the remaining elements from left and right halves, if any
while i < len(left):
arr[k] = left[i]
i += 1
k += 1
while j < len(right):
arr[k] = right[j]
j += 1
k += 1
# Example usage and analysis
arr = [38, 27, 43, 3, 9, 82, 10]
print("Original array:", arr)
merge_sort(arr)
print("Sorted array:", arr)
OUTPUT
Original array: [38, 27, 43, 3, 9, 82, 10]
Sorted array: [3, 9, 10, 27, 38, 43, 82]
RESULT:
Thus the python program to implement Fibonacci number using Recursion was
written,
executed and Verified successfully.
AIM:
To write a python program to implement merge sort analysis.
ALGORITHM:
● The quick_sort function recursively applies the quicksort algorithm.
● It chooses a pivot element from the array, partitions the array into elements
smaller than the pivot, equal to the pivot, and greater than the pivot, and then
recursively sorts the subarrays.
Ex.No: 3b
IMPLEMENTATION OF QUICK SORT
ANALYSIS
PROGRAM:
def quick_sort(arr):
if len(arr) <= 1:
return arr # Base case: already sorted if the array has 0 or 1 element
else:
pivot = arr[len(arr) // 2] # Choose the middle element as the pivot
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
# Example usage and analysis
arr = [38, 27, 43, 3, 9, 82, 10]
print("Original array:", arr)
sorted_array = quick_sort(arr)
print("Sorted array:", sorted_array)
OUTPUT
Original array: [38, 27, 43, 3, 9, 82, 10]
Sorted array: [3, 9, 10, 27, 38, 43, 82]
RESULT:
Thus the python program to implement Fibonacci number using Recursion was
written,
executed and Verified successfully.
AIM:
To write a python program for implementing Binary Search Tree.
ALGORITHM:
● The Node class represents a node in the binary search tree.
● The insert function inserts a new node into the BST based on the given key.
● The search function searches for a key in the BST and returns the node if
found.
Ex.No: 4
Date:
IMPLEMENTATION OF BINARY SEARCH TREE
PROGRAM:
class Node:
def __init__(self, key):
self.key = key
self.left = self.right = None
def insert(root, key):
if root is None:
return Node(key)
else:
if key < root.key:
root.left = insert(root.left, key)
elif key > root.key:
root.right = insert(root.right, key)
return root
def search(root, key):
if root is None or root.key == key:
return root
if key < root.key:
return search(root.left, key)
return search(root.right, key)
# Example usage and testing
root = None
keys = [50, 30, 20, 40, 70, 60, 80]
for key in keys:
root = insert(root, key)
search_key = int(input("Enter the search element: "))
result = search(root, search_key)
if result:
print(f"Element {search_key} found in the BST.")
else:
print(f"Element {search_key} not found in the BST.")
OUTPUT
Enter the search element: 60
Element 60 found in the BST.
.
RESULT:
Thus the implementation of Binary Search tree was written, executed and verified
successfully.
AIM:
To write a python program to implement Red-Black Tree.
ALGORITHM:
● The insert method is used to insert elements into the Red-Black Tree.
● The inorder_traversal method is used to visualize the Red-Black Tree using
inorder traversal.
Ex.No: 5
RED BLACK TREE IMPLEMENTATION
PROGRAM:
class Node:
def __init__(self, key, color='R'):
self.key = key
self.left = self.right = self.parent = None
self.color = color
class RedBlackTree:
def __init__(self):
self.NIL = Node(None, 'B') # NIL represents a null node
self.root = self.NIL
def insert(self, key):
# Step 1: Check whether the tree is empty
if self.root == self.NIL:
self.root = Node(key, 'B') # Insert the newNode as the root with color Black
else:
# Step 2: Insert the newNode as a leaf node with Red color
new_node = Node(key, 'R')
self._insert(new_node)
def _insert(self, node):
y = None
x = self.root
# Perform a regular binary search tree insert
while x != self.NIL:
y=x
if node.key < x.key:
x = x.left
else:
x = x.right
node.parent = y
if y == None:
self.root = node
elif node.key < y.key:
y.left = node
else:
y.right = node
# Insert may violate the Red-Black Tree properties, fix it
self._insert_fixup(node)
def _insert_fixup(self, node):
while node.parent and node.parent.color == 'R':
if node.parent == node.parent.parent.left:
y = node.parent.parent.right
if y and y.color == 'R':
node.parent.color = 'B'
y.color = 'B'
node.parent.parent.color = 'R'
node = node.parent.parent
else:
if node == node.parent.right:
node = node.parent
self.left_rotate(node)
node.parent.color = 'B'
node.parent.parent.color = 'R'
self.right_rotate(node.parent.parent)
else:
y = node.parent.parent.left
if y and y.color == 'R':
node.parent.color = 'B'
y.color = 'B'
node.parent.parent.color = 'R'
node = node.parent.parent
else:
if node == node.parent.left:
node = node.parent
self.right_rotate(node)
node.parent.color = 'B'
node.parent.parent.color = 'R'
self.left_rotate(node.parent.parent)
self.root.color = 'B' # Ensure the root is black
def left_rotate(self, x):
y = x.right
x.right = y.left
if y.left != self.NIL:
y.left.parent = x
y.parent = x.parent
if x.parent == None:
self.root = y
elif x == x.parent.left:
x.parent.left = y
else:
x.parent.right = y
y.left = x
x.parent = y
def right_rotate(self, x):
y = x.left
x.left = y.right
if y.right != self.NIL:
y.right.parent = x
y.parent = x.parent
if x.parent == None:
self.root = y
elif x == x.parent.right:
x.parent.right = y
else:
x.parent.left = y
y.right = x
x.parent = y
def inorder_traversal(self, node):
if node != self.NIL:
self.inorder_traversal(node.left)
print(f'{node.key} ({node.color}) ', end='')
self.inorder_traversal(node.right)
# Example usage
rb_tree = RedBlackTree()
keys = [50, 30, 20, 40, 70, 60, 80]
for key in keys:
rb_tree.insert(key)
print("Inorder Traversal of Red-Black Tree:")
rb_tree.inorder_traversal(rb_tree.root)
OUTPUT
Inorder Traversal of Red-Black Tree:
20 (B) 30 (B) 40 (R) 50 (B) 60 (R) 70 (B) 80 (R)
RESULT:
Thus the python program to implement Red Black Tree was executed and verified
successfully.
AIM:
To write a python program for heap implementation.
ALGORITHM:
● buildMaxHeap() is used to convert the array into a max heap.
● heapify() is a helper function to maintain the heap property during the build
process.
● heapSort() is the main sorting function that uses the max heap structure.
Ex.No: 6
HEAP IMPLEMENTATION
PROGRAM:
def buildMaxHeap(arr):
n = len(arr)
for i in range(n // 2 - 1, -1, -1):
heapify(arr, n, i)
def heapify(arr, n, i):
largest = i
left = 2 * i + 1
right = 2 * i + 2
if left < n and arr[left] > arr[largest]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
def heapSort(arr):
n = len(arr)
# Build max heap
buildMaxHeap(arr)
# Extract elements one by one
for i in range(n - 1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # Swap
heapify(arr, i, 0)
# Example usage and result
arr = [12, 11, 13, 5, 6, 7]
print("Original array:", arr)
heapSort(arr)
print("Sorted array:", arr)
OUTPUT
Original array: [12, 11, 13, 5, 6, 7]
Sorted array: [5, 6, 7, 11, 12, 13]
RESULT:
Thus the heap implementation was written, executed and verified successfully.
AIM:
To write a python program for Fibonacci heap implement.
ALGORITHM:
Initialization:
● FibonacciNode class represents a node in the Fibonacci Heap.
● FibonacciHeap class represents the Fibonacci Heap itself.
● Each node has a key, degree, marked status, references to child, parent,
next, and prev nodes.
● The heap has a min_node representing the minimum node and keeps
track of the number of nodes.
Insertion (insert method):
● Inserts a new node with the given key into the heap.
● If the heap is empty, the new node becomes the min_node.
● Otherwise, the new node is linked into the circular doubly linked list
using the _link method, and if its key is smaller than the current
minimum, it becomes the new minimum.
Finding Minimum (minimum method):
● Returns the key of the minimum node in the heap.
Extracting Minimum (extractMin method):
● Removes and returns the node with the minimum key from the heap.
● If the minimum node has children, they are added to the root list.
● The minimum node is removed from the root list, and consolidation is
performed using the _consolidate method to ensure that there is at
most one tree of each degree.
Decreasing Key (decreaseKey method):
● Decreases the key of a node to a new value.
● If the new key is smaller than the current key, the node is cut from its
parent and possibly marked. Cascading cuts are performed using the
_cut and _cascading_cut methods.
Deletion (delete method):
● Deletes a node from the heap by decreasing its key to negative in 昀椀 nity
and then extracting the minimum.
Union (union method):
● Merges another Fibonacci Heap with the current heap by linking their
root lists.
Linking (_link method):
Ex.No: 7
FIBONACCI HEAP IMPLEMENTATION
PROGRAM:
class FibonacciNode:
def __init__(self, key):
self.key = key
self.degree = 0
self.marked = False
self.child = None
self.parent = None
self.next = self
self.prev = self
class FibonacciHeap:
def __init__(self):
self.min_node = None
self.num_nodes = 0
def insert(self, key):
new_node = FibonacciNode(key)
if self.min_node is None:
self.min_node = new_node
else:
self._link(self.min_node, new_node)
if key < self.min_node.key:
self.min_node = new_node
self.num_nodes += 1
def minimum(self):
return self.min_node.key if self.min_node else None
def extractMin(self):
min_node = self.min_node
if min_node:
if min_node.child:
child = min_node.child
while child.parent:
next_child = child.next
min_node.child = next_child
self._add_node(child)
child.parent = None
child = next_child
prev_node = min_node.prev
next_node = min_node.next
prev_node.next = next_node
next_node.prev = prev_node
if min_node == min_node.next:
self.min_node = None
else:
self.min_node = next_node
self._consolidate()
self.num_nodes -= 1
return min_node.key if min_node else None
def decreaseKey(self, node, new_key):
if new_key > node.key:
raise ValueError("New key is greater than current key")
node.key = new_key
parent = node.parent
if parent and node.key < parent.key:
self._cut(node, parent)
self._cascading_cut(parent)
if node.key < self.min_node.key:
self.min_node = node
def delete(self, node):
self.decreaseKey(node, float('-inf'))
self.extractMin()
def union(self, other_heap):
if other_heap.min_node:
if self.min_node:
self._link(self.min_node, other_heap.min_node)
if other_heap.min_node.key < self.min_node.key:
self.min_node = other_heap.min_node
else:
self.min_node = other_heap.min_node
self.num_nodes += other_heap.num_nodes
def _link(self, root1, root2):
root2.prev.next = root1.next
root1.next.prev = root2.prev
root1.next = root2
root2.prev = root1
def _add_node(self, node):
node.next = node
node.prev = node
def _cut(self, child, parent):
if child.next == child:
parent.child = None
else:
next_child = child.next
prev_child = child.prev
next_child.prev = prev_child
prev_child.next = next_child
if parent.child == child:
parent.child = next_child
parent.degree -= 1
self._add_node(child)
child.parent = None
child.marked = False
def _cascading_cut(self, node):
parent = node.parent
if parent:
if not node.marked:
node.marked = True
else:
self._cut(node, parent)
self._cascading_cut(parent)
def _consolidate(self):
max_degree = int(self.num_nodes**0.5) + 1
degree_array = [None] * max_degree
current = self.min_node
nodes = []
while nodes.append(current) and current != self.min_node:
current = current.next
for node in nodes:
degree = node.degree
while degree_array[degree]:
other = degree_array[degree]
if node.key > other.key:
node, other = other, node
self._link(other, node)
degree_array[degree] = None
degree += 1
degree_array[degree] = node
self.min_node = None
for degree_node in degree_array:
if degree_node:
if self.min_node:
self._link(self.min_node, degree_node)
if degree_node.key < self.min_node.key:
self.min_node = degree_node
else:
self.min_node = degree_node
# Example usage and output for lab practice
fib_heap = FibonacciHeap()
keys = [4, 3, 7, 2, 8, 1, 6, 5]
print("Inserting keys into Fibonacci Heap:", keys)
for key in keys:
fib_heap.insert(key)
print("Minimum key in the Fibonacci Heap:", fib_heap.minimum())
print("Extracting Min from the Fibonacci Heap:")
while fib_heap.minimum() is not None:
print(fib_heap.extractMin())
OUTPUT
Inserting keys into Fibonacci Heap: [4, 3, 7, 2, 8, 1, 6, 5]
Minimum key in the Fibonacci Heap: 1
Extracting Min from the Fibonacci Heap:
1
2
3
4
5
6
7
8
RESULT:
Thus the Fibonacci heap implementation was written, executed and verified
successfully.
AIM:
To write a python program to implement graph traversal by using depth first
search.
ALGORITHM:
The Graph class uses an adjacency list to represent the graph.
The add_edge method adds edges to the graph.
The dfs method performs Depth First Search starting from a given node.
A stack is used to keep track of nodes to be visited.
The algorithm explores as far as possible along each branch before from
collections.
Ex.No: 8a
GRAPH TRAVERSALS (DEPTH FIRST SEARCH)
PROGRAM:
class Graph:
def __init__(self):
self.graph = defaultdict(list)
def add_edge(self, u, v):
self.graph[u].append(v)
self.graph[v].append(u)
def dfs(self, start):
visited = set() # To keep track of visited nodes
stack = [start] # Stack for DFS traversal
while stack:
current_node = stack.pop()
if current_node not in visited:
print(current_node, end=" ")
visited.add(current_node)
# Add adjacent nodes to the stack
stack.extend(neighbor for neighbor in self.graph[current_node] if neighbor not in
visited)
# Example Usage and Output for Lab Practice
graph = Graph()
graph.add_edge(1, 2)
graph.add_edge(1, 3)
graph.add_edge(2, 4)
graph.add_edge(2, 5)
graph.add_edge(3, 6)
graph.add_edge(3, 7)
print("Depth First Search (DFS) starting from node 1:")
graph.dfs(1)
OUTPUT:
Depth First Search (DFS) starting from node 1:
1376254
RESULT:
Thus the python program to implement graph traversal by using depth first search
was
written and verified successfully.
AIM:
To write a program to implement graph traversals by using breadth first search.
ALGORITHM:
The Graph class uses an adjacency list to represent the graph.
The add_edge method adds edges to the graph.
The bfs method performs Breadth First Search starting from a given node.
A queue is used to keep track of nodes to be visited.
The algorithm visits all neighbors of the current node before moving on to the
next level.
PROGRAM :
Ex.No: 8b
GRAPH TRAVERSALS (BREADTH FIRST SEARCH)
RESULT:
Thus the python program to implement graph traversal by using breadth first
search was
written, executed and verified successfully.
Ex.No: 9a
SPANNING TREE IMPLEMENTATION (KRUSKAL’S ALGORITHM)
AIM:
To write a python program to implement spanning tree implementation using
kruskal s ‟
algorithm.
ALGORITHM:
The Graph class initializes the graph with a given number of vertices.
The add_edge method adds edges to the graph.
The find_parent and union methods are used for 昀椀 nding the parent and
union operations in the disjoint-set data structure.
The kruskal method implements Kruskal's algorithm to 昀椀 nd the minimum
spanning tree.
The example usage creates a graph and 昀椀 nds the minimum spanning tree
using Kruskal's algorithm.
PROGRAM:
from collections import defaultdict, deque
class Graph:
def __init__(self):
self.graph = defaultdict(list)
def add_edge(self, u, v):
self.graph[u].append(v)
self.graph[v].append(u)
def bfs(self, start):
visited = set() # To keep track of visited nodes
queue = deque([start]) # Queue for BFS traversal
while queue:
current_node = queue.popleft()
if current_node not in visited:
print(current_node, end=" ")
visited.add(current_node)
# Add adjacent nodes to the queue
queue.extend(neighbor for neighbor in self.graph[current_node] if neighbor not in
visited)
# Example Usage and Output for Lab Practice
graph = Graph()
graph.add_edge(1, 2)
graph.add_edge(1, 3)
graph.add_edge(2, 4)
graph.add_edge(2, 5)
graph.add_edge(3, 6)
graph.add_edge(3, 7)
print("Breadth First Search (BFS) starting from node 1:")
graph.bfs(1)
OUTPUT
Minimum Spanning Tree (Kruskal's Algorithm):
Edge: 2 - 3, Weight: 4
Edge: 0 - 3, Weight: 5
Edge: 0 - 1, Weight: 10
RESULT:
Thus the Spanning tree implementation using kruskal s algorithm was written, ‟
executed and verified successfully.
AIM:
To write a python program to implement spanning tree implementation using Prim
s ‟ algorithm.
ALGORITHM:
The Graph class initializes the graph with a given number of vertices.
The add_edge method adds edges to the graph.
The prim method implements Prim's algorithm to 昀椀 nd the minimum spanning
tree.
The algorithm maintains a set of vertices (mst_set) included in the MST and
uses a min-heap to select the next vertex to be included.
The example usage creates a graph and 昀椀 nds the weight of the minimum
spanning tree using Prim's algorithm.
PROGRAM:
import heapq
Ex.No: 9b
SPANNING TREE IMPLEMENTATION (PRIM’S ALGORITHM)
class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = [[] for _ in range(vertices)]
def add_edge(self, u, v, w):
self.graph[u].append((v, w))
self.graph[v].append((u, w))
def prim(self):
mst_set = set()
min_heap = [(0, 0)] # (key, vertex) - heap to store vertices with their key values
total_weight = 0
key_values = [float('inf')] * self.V
key_values[0] = 0
while len(mst_set) < self.V:
key, u = heapq.heappop(min_heap)
if u not in mst_set:
mst_set.add(u)
total_weight += key
for v, weight in self.graph[u]:
if v not in mst_set and weight < key_values[v]:
key_values[v] = weight
heapq.heappush(min_heap, (weight, v))
return total_weight
# Example Usage and Output for Lab Practice
g = Graph(5)
g.add_edge(0, 1, 2)
g.add_edge(0, 3, 6)
g.add_edge(1, 2, 3)
g.add_edge(1, 3, 8)
g.add_edge(1, 4, 5)
g.add_edge(2, 4, 7)
g.add_edge(3, 4, 9)
print("Minimum Spanning Tree (Prim's Algorithm) Weight:", g.prim())
OUTPUT:
Minimum Spanning Tree (Prim's Algorithm) Weight: 16
RESULT:
Thus the Spanning tree implementation using prim’s algorithm was written,
executed and verified successfully.
AIM:
To write a pythan program to implement Dijkstra s Algorithm. ‟
ALGORITHM:
The Graph class initializes the graph with a given number of vertices.
The add_edge method adds edges to the graph.
The dijkstra method implements Dijkstra's algorithm to Find the shortest
distances from a given source vertex.
The algorithm uses a min-heap to e 昀케 ciently select the next vertex with the
smallest temporary distance.
The example usage creates a graph and 昀椀 nds the shortest distances from a
speci 昀椀 ed starting vertex.
PROGRAM:
Ex.No: 10a
SHORTEST PATH ALGORITHM (DIJKSTRA’S ALGORITHM)
import heapq
class Graph:
def __init__(self, vertices):
self.V = vertices
self.graph = [[] for _ in range(vertices)]
def add_edge(self, u, v, w):
self.graph[u].append((v, w))
def dijkstra(self, start):
min_heap = [(0, start)] # (distance, vertex) - heap to store vertices with their
distances
distances = [float('inf')] * self.V
distances[start] = 0
while min_heap:
dist_u, u = heapq.heappop(min_heap)
for v, weight in self.graph[u]:
new_dist = dist_u + weight
if new_dist < distances[v]:
distances[v] = new_dist
heapq.heappush(min_heap, (new_dist, v))
return distances
# Example Usage and Output for Lab Practice
g = Graph(6)
g.add_edge(0, 1, 4)
g.add_edge(0, 2, 2)
g.add_edge(1, 2, 5)
g.add_edge(1, 3, 10)
g.add_edge(2, 4, 3)
g.add_edge(3, 5, 7)
g.add_edge(4, 3, 1)
g.add_edge(4, 5, 8)
start_vertex = 0
shortest_distances = g.dijkstra(start_vertex)
print(f"Shortest Distances from Vertex {start_vertex}:")
for v, dist in enumerate(shortest_distances):
print(f"To Vertex {v}: {dist}")
OUTPUT
44
AIM:
To write a python program to implement Bellmann Ford algorithm.
ALGORITHM:
The Graph class initializes the graph with a given number of vertices.
The add_edge method adds edges to the graph.
The bellman_ford method implements the Bellman-Ford algorithm to 昀椀 nd the
shortest distances from a given source vertex.
The algorithm iterates through all edges multiple times to relax the path
distances.
It also checks for negative cycles by iterating through all edges one more
time.
Ex.No: 10b
SHORTEST PATH ALGARITHMS (BELLMANN FORD ALGORITHM)
PROGRAM:
class Graph:
def __init__(self, vertices):
self.V = vertices
self.edges = []
def add_edge(self, u, v, w):
self.edges.append((u, v, w))
def bellman_ford(self, start):
distances = [float('inf')] * self.V
distances[start] = 0
for _ in range(self.V - 1):
for u, v, weight in self.edges:
if distances[u] != float('inf') and distances[u] + weight < distances[v]:
distances[v] = distances[u] + weight
# Check for negative cycles
for u, v, weight in self.edges:
if distances[u] != float('inf') and distances[u] + weight < distances[v]:
raise ValueError("Graph contains a negative cycle")
return distances
# Example Usage and Output for Lab Practice
g = Graph(5)
g.add_edge(0, 1, 4)
g.add_edge(0, 2, 2)
g.add_edge(1, 2, 5)
g.add_edge(1, 3, 10)
g.add_edge(2, 4, 3)
g.add_edge(3, 5, 7)
g.add_edge(4, 3, 1)
g.add_edge(4, 5, 8)
start_vertex = 0
shortest_distances = g.bellman_ford(start_vertex)
print(f"Shortest Distances from Vertex {start_vertex}:")
for v, dist in enumerate(shortest_distances):
print(f"To Vertex {v}: {dist}")
OUTPUT
Shortest Distances from Vertex 0:
To Vertex 0: 0
To Vertex 1: 4
To Vertex 2: 2
To Vertex 3: 9
To Vertex 4: 5
To Vertex 5: 16
RESULT:
Thus the python program to implement Bellmann Ford Algorithm was written,
executed and verified successfully
AIM:
To write a python program to implement Matrix Chain Multiplication.
ALGORITHM:
A chain of matrices to be multiplied is given as input.
For a sequence A1,A2,A3,A4 of 4 matrices, there are 5 different orderings=5
different parenthesization.
o (A1,(A2(A3 A4)))
o (A1((A2 A3)A4))
o ((A1 A2)(A3 A4))
o ((A1(A2 A3))A4)
o (((A1 A2)A3)A4)
Matrix_Multiply(A,B)
If coloumns[A]!=rows[B]
Then error “incomplete dimensions”
Else for i <- 1 to rows[A]
Do for j <- 1 to columns[B]
Do c[I,j] <- 0
For k<- 1 to columns[A]
Do c[i,j]=C[i,j]+A[i,k]+B[i,j]
Return c
A parenthesizing of the chain of the matrices is obtained as output.
Ex.No: 11
MATRIX CHAIN MULTIPLICATION
PROGRAM:
def matrix_chain_multiplication(p):
n = len(p) - 1 # Number of matrices
m = [[0] * (n + 1) for _ in range(n + 1)] # Table to store minimum multiplication
cost
s = [[0] * (n + 1) for _ in range(n + 1)] # Table to store split points
for length in range(2, n + 1):
for i in range(1, n - length + 2):
j = i + length - 1
m[i][j] = float('inf')
for k in range(i, j):
cost = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j]
if cost < m[i][j]:
m[i][j] = cost
s[i][j] = k
return m, s
def print_optimal_parenthesization(s, i, j):
if i == j:
print(f"A{i}", end="")
else:
print("(", end="")
print_optimal_parenthesization(s, i, s[i][j])
print_optimal_parenthesization(s, s[i][j] + 1, j)
print(")", end="")
# Example Usage and Output for Lab Practice
matrix_dimensions = [30, 35, 15, 5, 10, 20, 25]
m_table, s_table = matrix_chain_multiplication(matrix_dimensions)
print("Minimum Multiplication Cost Table:")
for row in m_table:
print(row)
print("\nOptimal Parenthesization:")
print_optimal_parenthesization(s_table, 1, len(matrix_dimensions) - 1)
50
OUTPUT:
Minimum Multiplication Cost Table:
[0, 15750, 7875, 9375, 11875, 15125]
[0, 0, 2625, 4375, 7125, 10500]
[0, 0, 0, 750, 2500, 5375]
[0, 0, 0, 0, 1000, 3500]
[0, 0, 0, 0, 0, 5000]
[0, 0, 0, 0, 0, 0]
Optimal Parenthesization:
((A1(A2A3))((A4A5)A6))
RESULT:
Thus the python program to implement Matrix Chain Multiplication was written,
executed and
verified successfully.
AIM:
To write a python program to implement Activity Selection.
ALGORITHM:
Sort the activities as per finishing time in ascending order
Select the first activity
Select the new activity if its starting time is greater than or equal to the
previously
selected
activity
REPEAT step 3 till all activities are checked.
PROGRAM:
Ex.No: 12a
ACTIVITY SELECTION
AIM:
To write a python program to implement Huffman Coding
ALGORITHM:
Sort the message ensemble by decreasing probability.
N is the cardinal of the message ensemble (number of different messages).
Compute the integer n_0 such as 2<=n_0<=D and (N-n_0)/(D-1) is integer.
Select the n_0 least probable messages, and assign them each a digit code.
Substitute the selected messages by a composite message summing their
probability, and
re-order it.
While there remains more than one message, do steps thru 8.
Select D least probable messages, and assign them each a digit code.
Substitute the selected messages by a composite message summing their
probability, and
re-order it.
The code of each message is given by the concatenation of the code digits of the
aggregate they've been put in
.
PROGRAM:
Ex.No: 12b
HUFFMAN CODING
import heapq
from collections import defaultdict
class HuffmanNode:
def __init__(self, char, freq):
self.char = char
self.freq = freq
self.left = None
self.right = None
def __lt__(self, other):
return self.freq < other.freq
def build_huffman_tree(freq_map):
priority_queue = [HuffmanNode(char, freq) for char, freq in freq_map.items()]
heapq.heapify(priority_queue)
while len(priority_queue) > 1:
left_node = heapq.heappop(priority_queue)
right_node = heapq.heappop(priority_queue)
internal_node = HuffmanNode(None, left_node.freq + right_node.freq)
internal_node.left = left_node
internal_node.right = right_node
heapq.heappush(priority_queue, internal_node)
return priority_queue[0]
def build_huffman_codes(node, code="", mapping=None):
if mapping is None:
mapping = {}
if node.char is not None:
mapping[node.char] = code
if node.left is not None:
build_huffman_codes(node.left, code + "0", mapping)
if node.right is not None:
build_huffman_codes(node.right, code + "1", mapping)
return mapping
def huffman_coding(text):
freq_map = defaultdict(int)
for char in text:
freq_map[char] += 1
root = build_huffman_tree(freq_map)
codes = build_huffman_codes(root)
encoded_text = "".join(codes[char] for char in text)
return encoded_text, codes
# Example Usage and Output for Lab Practice
text_to_encode = "huffman coding is fun"
encoded_text, huffman_codes = huffman_coding(text_to_encode)
print("Original Text:", text_to_encode)
print("Encoded Text:", encoded_text)
print("Huffman Codes:")
for char, code in huffman_codes.items():
print(f"{char}: {code}")
OUTPUT
Original Text: huffman coding is fun
Encoded Text:
010101110111111111011010110110001100111110001101101001011110111000
1110100
1111001010101101
Huffman Codes:
h: 010
u: 11000
f: 011
m: 1111
a: 00
n: 11001
c: 1110
o: 1101
d: 100
i: 0100
g: 11101
s: 1000
: 1010
1: 10110
1: 10111
1: 101110
0: 101111
RESULT:
Thus the python program to implement Huffman Coding was written, executed and
verified
successfully.