Ads Lab Manual
Ads Lab Manual
import random
class BTreeNode:
self.t = t
self.leaf = leaf
self.keys = []
self.children = []
class BTree:
self.t = t
level += 1
if not node.leaf:
self.traverse(child, level)
if node is None:
node = self.root
i=0
i += 1
return node
if node.leaf:
return None
root = self.root
if len(root.keys) == 2 * self.t - 1:
s = BTreeNode(self.t, False)
self.root = s
s.children.append(root)
self.split_child(s, 0)
self.insert_non_full(s, k)
else:
self.insert_non_full(root, k)
i = len(node.keys) - 1
if node.leaf:
node.keys.append(None)
node.keys[i + 1] = node.keys[i]
i -= 1
node.keys[i + 1] = k
else:
while i >= 0 and k < node.keys[i]:
i -= 1
i += 1
if len(node.children[i].keys) == 2 * self.t - 1:
self.split_child(node, i)
if k > node.keys[i]:
i += 1
self.insert_non_full(node.children[i], k)
t = self.t
y = parent.children[i]
z = BTreeNode(t, y.leaf)
parent.children.insert(i + 1, z)
if not y.leaf:
y.children = y.children[0:t]
self._delete(self.root, k)
self.root = self.root.children[0]
t = self.t
idx = self._find_key(node, k)
if idx < len(node.keys) and node.keys[idx] == k:
if node.leaf:
node.keys.pop(idx)
else:
self._delete_internal(node, idx)
else:
if node.leaf:
return
if len(node.children[idx].keys) < t:
self._fill(node, idx)
self._delete(node.children[idx - 1], k)
else:
self._delete(node.children[idx], k)
idx = 0
idx += 1
return idx
t = self.t
k = node.keys[idx]
if len(node.children[idx].keys) >= t:
node.keys[idx] = pred
self._delete(node.children[idx], pred)
elif len(node.children[idx + 1].keys) >= t:
node.keys[idx] = succ
else:
self._merge(node, idx)
self._delete(node.children[idx], k)
cur = node.children[idx]
cur = cur.children[-1]
return cur.keys[-1]
cur = node.children[idx + 1]
cur = cur.children[0]
return cur.keys[0]
t = self.t
self._borrow_from_prev(node, idx)
self._borrow_from_next(node, idx)
else:
if idx != len(node.keys):
self._merge(node, idx)
else:
self._merge(node, idx - 1)
child = node.children[idx]
sibling = node.children[idx - 1]
if not child.leaf:
child.children.insert(0, sibling.children.pop())
node.keys[idx - 1] = sibling.keys.pop()
child = node.children[idx]
sibling = node.children[idx + 1]
child.keys.append(node.keys[idx])
if not sibling.leaf:
child.children.append(sibling.children.pop(0))
node.keys[idx] = sibling.keys.pop(0)
child = node.children[idx]
sibling = node.children[idx + 1]
child.keys.append(node.keys[idx])
child.keys.extend(sibling.keys)
if not child.leaf:
child.children.extend(sibling.children)
node.keys.pop(idx)
node.children.pop(idx + 1)
# Helper function to create random elements and test B-Tree
def test_btree():
t = 5 # Order of B-Tree
btree = BTree(t)
print("Inserting elements:")
for el in elements:
btree.insert(el)
print(f"Inserted {el}")
print("\nTraversing B-Tree:")
btree.traverse(btree.root)
search_value = random.choice(elements)
result = btree.search(search_value)
if result:
else:
delete_value = random.choice(elements)
print(f"\nDeleting {delete_value}:")
btree.delete(delete_value)
print(f"Deleted {delete_value}.")
print("\nTraversing B-Tree after deletion:")
btree.traverse(btree.root)
if __name__ == "__main__":
test_btree()
OUTPUT:
Inserting elements:
Inserted 940
Inserted 620
Inserted 2
Inserted 175
Inserted 365
Inserted 367
Inserted 380
Inserted 315
Inserted 674
Inserted 833
Inserted 855
Inserted 188
Inserted 437
Inserted 245
Inserted 484
Inserted 482
Inserted 941
Inserted 737
Inserted 130
Inserted 336
Inserted 578
Inserted 707
Traversing B-Tree:
Level 0 : [484]
Level 2 : [2, 11, 32, 40, 54, 67, 73, 84, 102]
Deleting 279:
Deleted 279.
Level 0 : [484]
Level 2 : [2, 11, 32, 40, 54, 67, 73, 84, 102]
Level 2 : [836, 848, 855, 859, 865, 868, 889, 908, 922]
3.Construct Min and Max Heap using arrays, delete any element and display the
content of the Heap.
MIN HEAP
To implement a Min Heap using arrays in Python, you need to manage heap operations such as
insertion, deletion, and displaying the heap. The Min Heap is a binary heap where the smallest
element is at the root, and each parent node is less than or equal to its child nodes.
class MinHeap:
def __init__(self):
self.heap = []
def extract_min(self):
if len(self.heap) == 0:
raise IndexError("Heap is empty")
min_value = self.heap[0]
last_value = self.heap.pop()
if len(self.heap) > 0:
self.heap[0] = last_value
self._heapify_down(0)
return min_value
if smallest != index:
self.heap[index], self.heap[smallest] = self.heap[smallest], self.heap[index]
self._heapify_down(smallest)
# Replace it with the last element and remove the last element
self.heap[index] = self.heap.pop()
def display(self):
print("Min Heap:", self.heap)
def main():
min_heap = MinHeap()
if __name__ == "__main__":
main()
OUTPUT
MAX HEAP
To implement a Max Heap using arrays in Python, you need to handle operations such as
insertion, deletion of arbitrary elements, and displaying the heap contents. A Max Heap is a
binary heap where each parent node is greater than or equal to its child nodes, and the largest
element is at the root.
class MaxHeap:
def __init__(self):
self.heap = []
return (index - 1) // 2
return 2 * index + 1
return 2 * index + 2
self.heap.append(key)
self._heapify_up(len(self.heap) - 1)
parent = self.parent(index)
self._heapify_up(parent)
def extract_max(self):
if len(self.heap) == 0:
max_value = self.heap[0]
last_value = self.heap.pop()
if len(self.heap) > 0:
self.heap[0] = last_value
self._heapify_down(0)
return max_value
largest = index
left = self.left_child(index)
right = self.right_child(index)
largest = left
largest = right
if largest != index:
self._heapify_down(largest)
if len(self.heap) == 0:
try:
index = self.heap.index(key)
except ValueError:
# Replace it with the last element and remove the last element
self.heap[index] = self.heap.pop()
self._heapify_down(index)
self._heapify_up(index)
def display(self):
def main():
max_heap = MaxHeap()
max_heap.insert(10)
max_heap.insert(5)
max_heap.insert(15)
max_heap.insert(20)
max_heap.insert(8)
max_heap.display()
max_heap.display()
max_heap.display()
if __name__ == "__main__":
main()
OUTPUT
Extracted Max: 20
4. Implement BFT and DFT for given graph, when graph is represented by
Adjacency Matrix
Adjacency Lists
Adjacency Matrix
To implement Breadth-First Traversal (BFT) and Depth-First Traversal (DFT) for a graph
represented by an adjacency matrix, we'll create a Python program that includes the following
steps:
class Graph:
self.adj_matrix = adjacency_matrix
self.num_vertices = len(adjacency_matrix)
queue = deque([start_vertex])
visited[start_vertex] = True
result = []
while queue:
vertex = queue.popleft()
result.append(vertex)
for i in range(self.num_vertices):
queue.append(i)
visited[i] = True
return result
result = []
return result
def _dfs_util(self, vertex, visited, result):
visited[vertex] = True
result.append(vertex)
for i in range(self.num_vertices):
def main():
adj_matrix = [
[0, 1, 1, 0],
[1, 0, 1, 1],
[1, 1, 0, 1],
[0, 1, 1, 0]
graph = Graph(adj_matrix)
start_vertex = 0
# Breadth-First Traversal
print(graph.bfs(start_vertex))
# Depth-First Traversal
print(graph.dfs(start_vertex))
if __name__ == "__main__":
main()
OUTPUT
[0, 1, 2, 3]
[0, 1, 2, 3]
ADJACENCY LIST
class GraphList:
self.adj_list = adjacency_list
self.num_vertices = len(adjacency_list)
queue = deque([start_vertex])
visited[start_vertex] = True
result = []
while queue:
vertex = queue.popleft()
result.append(vertex)
queue.append(neighbor)
visited[neighbor] = True
return result
result = []
return result
visited[vertex] = True
result.append(vertex)
if not visited[neighbor]:
def main_list():
adj_list = {
0: [1, 2],
1: [0, 2, 3],
2: [0, 1, 3],
3: [1, 2]
graph = GraphList(adj_list)
start_vertex = 0
# Breadth-First Traversal
print(graph.bfs(start_vertex))
# Depth-First Traversal
print(graph.dfs(start_vertex))
if __name__ == "__main__":
main_list()
OUTPUT:
[0, 1, 2, 3]
[0, 1, 2, 3]
5. Write a program for finding the biconnected components in a given graph
class Graph:
def __init__(self, vertices):
self.vertices = vertices
self.adj_list = defaultdict(list)
def biconnected_components(self):
# Initialize required variables
time = [0]
stack = []
bccs = []
visited = set()
disc = {}
low = {}
parent = {}
def dfs(u):
visited.add(u)
disc[u] = low[u] = time[0]
time[0] += 1
children = 0
for v in self.adj_list[u]:
if v not in visited:
stack.append((u, v)) # Store the edge in stack
parent[v] = u
children += 1
dfs(v)
# If the lowest vertex reachable from subtree under v is below u in DFS tree, then u-v is a
bridge
if low[v] >= disc[u]:
bcc = []
while stack[-1] != (u, v):
bcc.append(stack.pop())
bcc.append(stack.pop())
bccs.append(bcc)
return bccs
def main():
# Example graph
g = Graph(5)
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 2)
g.add_edge(1, 3)
g.add_edge(2, 4)
g.add_edge(3, 4)
print("Biconnected Components:")
bccs = g.biconnected_components()
for i, bcc in enumerate(bccs):
print(f"Biconnected Component {i + 1}: {bcc}")
if __name__ == "__main__":
main()
OUTPUT
Biconnected Components:
Biconnected Component 1: [(3, 1), (4, 3), (2, 4), (2, 0), (1, 2), (0, 1)]