0% found this document useful (0 votes)
12 views40 pages

K.R. Mangalam University: Data Structure Lab Manual

Uploaded by

rcvikram2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views40 pages

K.R. Mangalam University: Data Structure Lab Manual

Uploaded by

rcvikram2005
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 40

K.R.

Mangalam University

Data Structure Lab Manual

Subject code : ENBC253

Submitted to : Submitted By :
Mr. Rahul Singh R C Vikram
Assistant Professor 2301840007
CSE SOET B.sc(Hons.) Data Science
Index
Serial Experiment Date Signature
No

01 Exploring Array Data Structure.

02 Implementing and Analyzing Stack


Data Structure.

03 Implementing and Analyzing Queue Data


Structure.

04 Implementing and Analyzing Linked-


List Data Structure and its Operation.

05 Implementing and Analyzing Binary


Search Tree Structure and its Operations.

06 Graph Representation and Traversal.

07 Implementing and Comparing Searching


Algorithms.

08 Implementing and Comparing Sorting


Algorithms.
Data Structure Lab

Assignments 1

Q. Exploring Array Data Structure - Operations implement inserting


elements at the end of an array, at any specific position, and maintaining a
sorted array. Analyze the time and space complexity of these operations.

Code -

class ArrayOperations:
def __init__(self, capacity):
self.array = []
self.capacity = capacity

def insert_at_end(self, element):


if len(self.array) < self.capacity:
self.array.append(element)
else:
print("Error: Array is full!")

def insert_at_position(self, position, element):


if position < 0 or position > len(self.array):
print("Error: Invalid position!")
elif len(self.array) < self.capacity:
self.array.insert(position, element)
else:
print("Error: Array is full!")

def insert_sorted(self, element):


if len(self.array) < self.capacity:
self.array.append(element)
self.array.sort()
else:
print("Error: Array is full!")

def display(self)
print("Current Array:", self.array)

R C Vikram
Data Structure Lab

array = ArrayOperations(capacity=5)
array.insert_at_end(10)
array.insert_at_end(20)
array.insert_at_position(1, 15)
array.insert_sorted(5)
array.insert_sorted(25)
array.display()

Output-

Current Array: [5, 10, 15, 20, 25]

Analysis of Time and Space Complexity

● Insertion at End: O(1)O(1)O(1)


● Insertion at Position: O(n)O(n)O(n) (shifting required)
● Maintaining Sorted Array: O(nlogn)O(n \log n)O(nlogn) for sorting,
O(n)O(n)O(n) for shifting
● Space Complexity: O(n)O(n)O(n), where nnn is the array size.

R C Vikram

Data Structure Lab

Assignment 2

Q. Implementing and Analyzing Stack Data Structure - perform operations


Push and Pop, implementation to solve problems related to postfix and prefix
expressions.

Code-

class Stack:
def __init__(self, capacity):
self.stack = []
self.capacity = capacity

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

def is_full(self):
return len(self.stack) == self.capacity

def push(self, element):


if not self.is_full():
self.stack.append(element)
else:
print("Stack Overflow! Cannot push more elements.")

def pop(self):
if not self.is_empty():
return self.stack.pop()
else:
print("Stack Underflow! Stack is empty.")
return None

def peek(self):
if not self.is_empty():
return self.stack[-1]

R C Vikram
Data Structure Lab

else:
return None

def display(self):
print("Current Stack:", self.stack)

stack = Stack(5)
stack.push(10)
stack.push(20)
stack.push(30)
stack.display()
print("Popped:", stack.pop())
stack.display()

Output-

Current Stack: [10, 20, 30]


Popped: 30
Current Stack: [10, 20]

1. Implementation of solving postfix expressions.

Code-

def evaluate_postfix(expression):
stack = Stack(len(expression))

for char in expression:


if char.isdigit(): # Operand
stack.push(int(char))
else: # Operator
b = stack.pop()
a = stack.pop()

R C Vikram
Data Structure Lab

if char == '+':
stack.push(a + b)
elif char == '-':
stack.push(a - b)
elif char == '*':
stack.push(a * b)
elif char == '/':
stack.push(a // b)

return stack.pop()

postfix_expr = "53+62/*"
print("Postfix Evaluation:", evaluate_postfix(postfix_expr))

Output-

Postfix Evaluation: 0

2. Implementation of solving postfix expressions.

Code-

def evaluate_prefix(expression):
stack = Stack(len(expression))

for char in reversed(expression):


if char.isdigit():
stack.push(int(char))
else:
a = stack.pop()
b = stack.pop()
if char == '+':

R C Vikram
Data Structure Lab

stack.push(a + b)
elif char == '-':
stack.push(a - b)
elif char == '*':
stack.push(a * b)
elif char == '/':
stack.push(a // b)

return stack.pop()

prefix_expr = "+*23/62"
print("Prefix Evaluation:", evaluate_prefix(prefix_expr))

Output-

Prefix Evaluation: 9

3. Apply Stack to Solve the Tower of Hanoi

Code-

def tower_of_hanoi(n, source, auxiliary, target):


if n == 1:
print(f"Move disk 1 from {source} to {target}")
return
tower_of_hanoi(n - 1, source, target, auxiliary)
print(f"Move disk {n} from {source} to {target}")
tower_of_hanoi(n - 1, auxiliary, source, target)

print("Tower of Hanoi Solution:")


tower_of_hanoi(3, 'A', 'B', 'C')

R C Vikram
Data Structure Lab

Output -

Tower of Hanoi Solution:


Move disk 1 from A to C
Move disk 2 from A to B
Move disk 1 from C to B
Move disk 3 from A to C
Move disk 1 from B to A
Move disk 2 from B to C
Move disk 1 from A to C

R C Vikram
Data Structure Lab

Assignment 3

Q. Implementing and Analyzing Queue Data Structure- Implements and


explores the Queue data structure. You will perform insertion and deletion
operations for both standard and circular queues and simulate CPU
scheduling algorithms, such as Round Robin, using queues

Code - Standard queue

class StandardQueue:
def __init__(self):
self.queue = []

def enqueue(self, item):


self.queue.append(item)
print(f"Enqueued: {item}")

def dequeue(self):
if not self.is_empty():
removed_item = self.queue.pop(0)
print(f"Dequeued: {removed_item}")
return removed_item
else:
print("Queue is empty!")
return None

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

def display(self):
print("Queue contents:", self.queue)

print("Standard Queue Example:")


sq = StandardQueue()
sq.enqueue(10)
sq.enqueue(20)

R C Vikram
Data Structure Lab

sq.dequeue()
sq.display()

Output -

Standard Queue Example:


Enqueued: 10
Enqueued: 20
Dequeued: 10
Queue contents: [20]

Code - Circular queue

class CircularQueue:
def __init__(self, size):
self.queue = [None] * size
self.size = size
self.front = self.rear = -1

def enqueue(self, item):


if (self.rear + 1) % self.size == self.front:
print("Queue is full!")
return
elif self.front == -1: # First insertion
self.front = 0
self.rear = (self.rear + 1) % self.size
self.queue[self.rear] = item
print(f"Enqueued: {item}")

def dequeue(self):
if self.front == -1: # Queue is empty
print("Queue is empty!")
return None
removed_item = self.queue[self.front]
self.queue[self.front] = None

R C Vikram
Data Structure Lab

if self.front == self.rear: # Single element left


self.front = self.rear = -1
else:
self.front = (self.front + 1) % self.size
print(f"Dequeued: {removed_item}")
return removed_item

def display(self):
print("Queue contents:", self.queue)

print("\nCircular Queue Example:")


cq = CircularQueue(3)
cq.enqueue(10)
cq.enqueue(20)
cq.enqueue(30)
cq.dequeue()
cq.enqueue(40)
cq.display()

Output -

Enqueued: 10
Enqueued: 20
Enqueued: 30
Dequeued: 10
Enqueued: 40
Queue contents: [40, 20, 30]

R C Vikram
Data Structure Lab

CPU Scheduling (Round Robin) Using Queue

Code -

class RoundRobin:
def __init__(self, time_quantum):
self.time_quantum = time_quantum
self.processes = []

def add_process(self, pid, burst_time):


self.processes.append({"pid": pid, "burst_time": burst_time})
print(f"Process {pid} with burst time {burst_time} added.")

def execute(self):
print("\nRound Robin Execution:")
while self.processes:
process = self.processes.pop(0)
pid, burst_time = process["pid"], process["burst_time"]
if burst_time > self.time_quantum:
print(f"Executing process {pid} for {self.time_quantum} units.")
burst_time -= self.time_quantum
self.processes.append({"pid": pid, "burst_time": burst_time})
else:
print(f"Executing process {pid} for {burst_time} units. Process complete.")
self.display_queue()

def display_queue(self):
print("Remaining queue:", [p["pid"] for p in self.processes])

print("\nRound Robin Scheduling Example:")


rr = RoundRobin(time_quantum=3)
rr.add_process("P1", 5)
rr.add_process("P2", 8)
rr.add_process("P3", 2)
rr.execute()

R C Vikram
Data Structure Lab

Output -

Round Robin Scheduling Example:


Process P1 with burst time 5 added.
Process P2 with burst time 8 added.
Process P3 with burst time 2 added.

Round Robin Execution:


Executing process P1 for 3 units.
Remaining queue: ['P2', 'P3', 'P1']
Executing process P2 for 3 units.
Remaining queue: ['P3', 'P1', 'P2']
Executing process P3 for 2 units. Process complete.
Remaining queue: ['P1', 'P2']
Executing process P1 for 2 units. Process complete.
Remaining queue: ['P2']
Executing process P2 for 2 units. Process complete.
Remaining queue: []

R C Vikram
Data Structure Lab

Assignment 4

Q. Implementing and Analyzing Linked-List Data Structure and its


Operations- implement various operations on singly, doubly, and circular
linked lists. develop a contact management system using linked lists, which
will involve adding, deleting, and searching for contacts.

Singly Linked List Implementation

Code -

class Node:
def __init__(self, data):
self.data = data
self.next = None

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

def insert_at_end(self, data):


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

def delete(self, key):


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

if self.head.data == key:

R C Vikram
Data Structure Lab

self.head = self.head.next
return

current = self.head
while current.next and current.next.data != key:
current = current.next

if current.next:
current.next = current.next.next
else:
print(f"Key {key} not found!")

def display(self):
current = self.head
while current:
print(current.data, end=" -> ")
current = current.next
print("None")

print("Singly Linked List:")


sll = SinglyLinkedList()
sll.insert_at_end("Alice")
sll.insert_at_end("Bob")
sll.insert_at_end("Charlie")
sll.display()
sll.delete("Bob")
sll.display()

Output -

Singly Linked List:


Alice -> Bob -> Charlie -> None
Alice -> Charlie -> None

R C Vikram
Data Structure Lab

Doubly Linked List Implementation

Code -

class DNode:
def __init__(self, data):
self.data = data
self.next = None
self.prev = None

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

def insert_at_end(self, data):


new_node = DNode(data)
if not self.head:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
new_node.prev = current

def delete(self, key):


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

current = self.head
while current and current.data != key:
current = current.next

if current:
if current.prev:
current.prev.next = current.next
if current.next:
current.next.prev = current.prev
if current == self.head:

R C Vikram
Data Structure Lab

self.head = current.next

def display(self):
current = self.head
while current:
print(current.data, end=" <-> ")
current = current.next
print("None")

print("\nDoubly Linked List:")


dll = DoublyLinkedList()
dll.insert_at_end("Alice")
dll.insert_at_end("Bob")
dll.insert_at_end("Charlie")
dll.display()
dll.delete("Bob")
dll.display()

Output -

Doubly Linked List:


Alice <-> Bob <-> Charlie <-> None
Alice <-> Charlie <-> None

R C Vikram
Data Structure Lab

Circular Linked List Implementation

Code-

class CNode:
def __init__(self, data):
self.data = data
self.next = None

class CircularLinkedList:
def __init__(self):
self.tail = None

def insert_at_end(self, data):


new_node = CNode(data)
if not self.tail:
self.tail = new_node
self.tail.next = new_node
else:
new_node.next = self.tail.next
self.tail.next = new_node
self.tail = new_node

def delete(self, key):


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

current = self.tail.next
prev = self.tail

while current.data != key and current != self.tail:


prev = current
current = current.next

if current.data == key:
if current == self.tail and current.next == self.tail: # Only one node
self.tail = None
elif current == self.tail:
prev.next = self.tail.next

R C Vikram
Data Structure Lab

self.tail = prev
else:
prev.next = current.next

def display(self):
if not self.tail:
print("List is empty!")
return

current = self.tail.next
while True:
print(current.data, end=" -> ")
current = current.next
if current == self.tail.next:
break
print("(Back to start)")

print("\nCircular Linked List:")


cll = CircularLinkedList()
cll.insert_at_end("Alice")
cll.insert_at_end("Bob")
cll.insert_at_end("Charlie")
cll.display()
cll.delete("Bob")
cll.display()

Output -

Circular Linked List:


Alice -> Bob -> Charlie -> (Back to start)
Alice -> Charlie -> (Back to start)

R C Vikram
Data Structure Lab

Contact Management System Using Singly Linked List

Code-

class Contact:
def __init__(self, name, phone):
self.name = name
self.phone = phone

def __str__(self):
return f"Name: {self.name}, Phone: {self.phone}"

class ContactManagementSystem:
def __init__(self):
self.contacts = SinglyLinkedList()

def add_contact(self, name, phone):


contact = Contact(name, phone)
self.contacts.insert_at_end(contact)
print(f"Contact {name} added.")

def delete_contact(self, name):


current = self.contacts.head
while current:
if current.data.name == name:
self.contacts.delete(current.data)
print(f"Contact {name} deleted.")
return
current = current.next
print(f"Contact {name} not found!")

def search_contact(self, name):


current = self.contacts.head
while current:
if current.data.name == name:
print(f"Found Contact: {current.data}")
return
current = current.next
print(f"Contact {name} not found!")

R C Vikram
Data Structure Lab

def display_contacts(self):
print("Contact List:")
current = self.contacts.head
while current:
print(current.data)
current = current.next

print("\nContact Management System:")


cms = ContactManagementSystem()
cms.add_contact("Alice", "1234567890")
cms.add_contact("Bob", "9876543210")
cms.display_contacts()
cms.search_contact("Alice")
cms.delete_contact("Bob")
cms.display_contacts()

Output -

Contact Management System:


Contact Alice added.
Contact Bob added.
Contact List:
Name: Alice, Phone: 1234567890
Name: Bob, Phone: 9876543210
Found Contact: Name: Alice, Phone: 1234567890
Contact Bob deleted.
Contact List:
Name: Alice, Phone: 1234567890

R C Vikram
Data Structure Lab

Assignment 5

Q. Implementing and Analyzing Binary Search Tree Structure and its Operations-
implement and explore various operations on a Binary Search Tree (BST). Include
insertion, deletion, and searching for nodes within the BST. Create a program to
manage hierarchical data, such as an organizational chart, using the BST

Binary Search Tree Implementation

Code -

class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None

class BinarySearchTree:
def __init__(self):
self.root = None

def insert(self, key):


self.root = self._insert(self.root, key)

def _insert(self, node, key):


if node is None:
return Node(key)
if key < node.key:
node.left = self._insert(node.left, key)
else:
node.right = self._insert(node.right, key)
return node

def delete(self, key):


self.root = self._delete(self.root, key)

def _delete(self, node, key):

R C Vikram
Data Structure Lab

if node is None:
return node
if key < node.key:
node.left = self._delete(node.left, key)
elif key > node.key:
node.right = self._delete(node.right, key)
else:

if node.left is None:
return node.right
elif node.right is None:
return node.left

temp = self._min_value_node(node.right)
node.key = temp.key
node.right = self._delete(node.right, temp.key)
return node

def _min_value_node(self, node):


current = node
while current.left:
current = current.left
return current

def search(self, key):


return self._search(self.root, key)

def _search(self, node, key):


if node is None or node.key == key:
return node
if key < node.key:
return self._search(node.left, key)
return self._search(node.right, key)

def inorder(self):
result = []
self._inorder(self.root, result)
return result

R C Vikram
Data Structure Lab

def _inorder(self, node, result):


if node:
self._inorder(node.left, result)
result.append(node.key)
self._inorder(node.right, result)

print("Binary Search Tree Operations:")


bst = BinarySearchTree()
elements = [50, 30, 20, 40, 70, 60, 80]

for el in elements:
bst.insert(el)

print("Inorder Traversal after Insertion:", bst.inorder())

key = 40
found = bst.search(key)
print(f"Element {key} {'found' if found else 'not found'} in the BST.")

bst.delete(30)
print("Inorder Traversal after Deletion of 30:", bst.inorder())

Output -

Binary Search Tree Operations:


Inorder Traversal after Insertion: [20, 30, 40, 50, 60, 70, 80]
Element 40 found in the BST.
Inorder Traversal after Deletion of 30: [20, 40, 50, 60, 70, 80]

R C Vikram
Data Structure Lab

Organizational Chart Using BST

Code -

class OrgNode:
def __init__(self, name, role):
self.name = name
self.role = role
self.left = None
self.right = None

def __str__(self):
return f"{self.name} ({self.role})"

class OrganizationTree:
def __init__(self):
self.root = None

def add_employee(self, name, role):


self.root = self._add_employee(self.root, name, role)

def _add_employee(self, node, name, role):


if node is None:
return OrgNode(name, role)
if name < node.name:
node.left = self._add_employee(node.left, name, role)
else:
node.right = self._add_employee(node.right, name, role)
return node

def display_hierarchy(self):
self._display_hierarchy(self.root, 0)

def _display_hierarchy(self, node, level):


if node:
self._display_hierarchy(node.right, level + 1)
print(" " * level + str(node))
self._display_hierarchy(node.left, level + 1)

R C Vikram
Data Structure Lab

print("\nOrganizational Chart:")
org_tree = OrganizationTree()
org_tree.add_employee("Alice", "CEO")
org_tree.add_employee("Bob", "CTO")
org_tree.add_employee("Charlie", "CFO")
org_tree.add_employee("David", "Engineer")
org_tree.add_employee("Eve", "Accountant")

org_tree.display_hierarchy()

Output -

Organizational Chart:
Eve (Accountant)
Charlie (CFO)
Alice (CEO)
David (Engineer)
Bob (CTO)

R C Vikram
Data Structure Lab

Assignment 6

Q. Graph Representation and Traversal- Implement graph representation


using both adjacency matrices and adjacency lists, also perform
Breadth-First Search (BFS) and Depth-First Search (DFS) traversals on the
graph. Additionally you will develop a network analysis tool that finds the
shortest path between nodes using the graph.

1. Adjacency Matrix Representation

Code -

class GraphMatrix:
def __init__(self, vertices):
self.V = vertices
self.graph = [[0 for _ in range(vertices)] for _ in range(vertices)]

def add_edge(self, u, v, weight=1):


self.graph[u][v] = weight
self.graph[v][u] = weight

def display(self):
print("Adjacency Matrix:")
for row in self.graph:
print(row)

matrix_graph = GraphMatrix(5)
matrix_graph.add_edge(0, 1, 2)
matrix_graph.add_edge(0, 2, 4)
matrix_graph.add_edge(1, 3, 7)
matrix_graph.add_edge(2, 4, 1)

matrix_graph.display()

R C Vikram
Data Structure Lab

Output -

Adjacency Matrix:
[0, 2, 4, 0, 0]
[2, 0, 0, 7, 0]
[4, 0, 0, 0, 1]
[0, 7, 0, 0, 0]
[0, 0, 1, 0, 0]

2. Adjacency List Representation

Code -

from collections import defaultdict

class GraphList:
def __init__(self, vertices):
self.V = vertices
self.graph = defaultdict(list)

def add_edge(self, u, v, weight=1):


self.graph[u].append((v, weight))
self.graph[v].append((u, weight))

def display(self):
print("Adjacency List:")
for vertex, edges in self.graph.items():
print(f"{vertex}: {edges}")

list_graph = GraphList(5)
list_graph.add_edge(0, 1, 2)
list_graph.add_edge(0, 2, 4)
list_graph.add_edge(1, 3, 7)
list_graph.add_edge(2, 4, 1)

R C Vikram
Data Structure Lab

list_graph.display()

Output -
Adjacency List:
0: [(1, 2), (2, 4)]
1: [(0, 2), (3, 7)]
2: [(0, 4), (4, 1)]
3: [(1, 7)]
4: [(2, 1)]

3. Breadth-First Search (BFS)

Code -

def bfs(graph, start):


visited = [False] * len(graph)
queue = [start]
visited[start] = True
print("BFS Traversal:")
while queue:
node = queue.pop(0)
print(node, end=" ")
for neighbor, _ in graph[node]:
if not visited[neighbor]:
queue.append(neighbor)
visited[neighbor] = True
print()

bfs(list_graph.graph, 0)

Output -

BFS Traversal:
01234

R C Vikram
Data Structure Lab

4. Depth-First Search (DFS)

Code -

def dfs(graph, start, visited=None):


if visited is None:
visited = [False] * len(graph)
visited[start] = True
print(start, end=" ")
for neighbor, _ in graph[start]:
if not visited[neighbor]:
dfs(graph, neighbor, visited)

print("DFS Traversal:")
dfs(list_graph.graph, 0)
print()

Output -

DFS Traversal:
01324

5. Shortest Path (Dijkstra’s Algorithm)

Code -

import heapq

def dijkstra(graph, start):


distances = {node: float('inf') for node in graph}
distances[start] = 0
pq = [(0, start)] # Priority queue
print("Shortest Path from Node 0:")

R C Vikram
Data Structure Lab

while pq:
current_distance, current_node = heapq.heappop(pq)
if current_distance > distances[current_node]:
continue
for neighbor, weight in graph[current_node]:
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(pq, (distance, neighbor))

for node, dist in distances.items():


print(f"Node {node}: Distance {dist}")

dijkstra(list_graph.graph, 0)

Output -

Shortest Path from Node 0:


Node 0: Distance 0
Node 1: Distance 2
Node 2: Distance 4
Node 3: Distance 9
Node 4: Distance 5

R C Vikram
Data Structure Lab

Assignment 7

Q. Implementing and Comparing Searching Algorithms - Implement linear search


and binary search algorithms Both searches should be implemented in their
recursive and nonrecursive forms then compare the efficiency of these algorithms in
terms of time and space complexity. l develop a search feature for a text-based
database application that utilizes these searching algorithms.

1. Linear Search
Non-Recursive Linear Search:

Code -

def linear_search(arr, target):


for i in range(len(arr)):
if arr[i] == target:
return i
return -1

arr = [10, 20, 30, 40, 50]


target = 30
result = linear_search(arr, target)
print(f"Non-Recursive Linear Search: Element found at index {result}" if result != -1 else
"Element not found")

Output -

Non-Recursive Linear Search: Element found at index 2

R C Vikram
Data Structure Lab

Recursive Linear Search:

Code -

def recursive_linear_search(arr, target, index=0):


if index >= len(arr):
return -1
if arr[index] == target:
return index
return recursive_linear_search(arr, target, index + 1)

result = recursive_linear_search(arr, target)


print(f"Recursive Linear Search: Element found at index {result}" if result != -1 else
"Element not found")

Output -

Recursive Linear Search: Element found at index 2

2. Binary Search
Non-Recursive Binary Search:

Code -

def binary_search(arr, target):


low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1

R C Vikram
Data Structure Lab

arr = [10, 20, 30, 40, 50] # Must be sorted


target = 30
result = binary_search(arr, target)
print(f"Non-Recursive Binary Search: Element found at index {result}" if result != -1 else
"Element not found")

Output -

Non-Recursive Binary Search: Element found at index 2

Recursive Binary Search:

Code -

def recursive_binary_search(arr, target, low, high):


if low > high:
return -1
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
return recursive_binary_search(arr, target, mid + 1, high)
else:
return recursive_binary_search(arr, target, low, mid - 1)

result = recursive_binary_search(arr, target, 0, len(arr) - 1)


print(f"Recursive Binary Search: Element found at index {result}" if result != -1 else
"Element not found")

Output -

Recursive Binary Search: Element found at index 2

R C Vikram
Data Structure Lab

Efficiency Comparison:

● Linear Search:
○ Time Complexity: O(n)O(n)O(n)
○ Space Complexity: O(1)O(1)O(1) for non-recursive, O(n)O(n)O(n) for
recursive due to call stack.
● Binary Search:
○ Time Complexity: O(logn)O(\log n)O(logn)
○ Space Complexity: O(1)O(1)O(1) for non-recursive, O(logn)O(\log
n)O(logn) for recursive due to call stack

3. Search Feature for a Text-Based Database Application

Code -

class TextDatabase:
def __init__(self):
self.data = []

def add_record(self, record):


self.data.append(record)
self.data.sort() # Keep data sorted for binary search

def search_record(self, target, method="binary"):


if method == "binary":
return binary_search(self.data, target)
elif method == "linear":
return linear_search(self.data, target)
else:

R C Vikram


Data Structure Lab

raise ValueError("Invalid search method")

db = TextDatabase()
db.add_record("Alice")
db.add_record("Bob")
db.add_record("Charlie")
db.add_record("David")

target = "Charlie"
result = db.search_record(target, method="binary")
print(f"Database Search: '{target}' found at index {result}" if result != -1 else f"'{target}'
not found")

Output -

Database Search: 'Charlie' found at index 1

R C Vikram
Data Structure Lab

Assignment 8

Q. Implementing and Comparing Sorting Algorithms - Implement several sorting


algorithms, including Bubble Sort, Quick Sort, and Merge Sort , compare their
performance in terms of efficiency and effectiveness. Apply these sorting techniques
to sort large datasets efficiently, demonstrating their usefulness in data analysis
applications.

1. Bubble Sort

Code -

def bubble_sort(arr):
n = len(arr)
for i in range(n - 1):
for j in range(n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr

data = [64, 34, 25, 12, 22, 11, 90]


sorted_data = bubble_sort(data)
print("Bubble Sort Output:", sorted_data)

Output -

Bubble Sort Output: [11, 12, 22, 25, 34, 64, 90]

R C Vikram
Data Structure Lab

2. Quick Sort

Code -

def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
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)

data = [64, 34, 25, 12, 22, 11, 90]


sorted_data = quick_sort(data)
print("Quick Sort Output:", sorted_data)

Output -

Quick Sort Output: [11, 12, 22, 25, 34, 64, 90]

3. Merge Sort

Code -

def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
left_half = arr[:mid]
right_half = arr[mid:]

merge_sort(left_half)
merge_sort(right_half)

i=j=k=0

R C Vikram
Data Structure Lab

while i < len(left_half) and j < len(right_half):


if left_half[i] < right_half[j]:
arr[k] = left_half[i]
i += 1
else:
arr[k] = right_half[j]
j += 1
k += 1

while i < len(left_half):


arr[k] = left_half[i]
i += 1
k += 1

while j < len(right_half):


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

data = [64, 34, 25, 12, 22, 11, 90]


merge_sort(data)
print("Merge Sort Output:", data)

Output -

Merge Sort Output: [11, 12, 22, 25, 34, 64, 90]

Comparison of Performance

● Bubble Sort: Inefficient for large datasets due to O(n2)O(n^2)O(n2) time


complexity.
● Quick Sort: Efficient for large datasets with an average time complexity of
O(nlogn)O(n \log n)O(nlogn).
● Merge Sort: Guarantees O(nlogn)O(n \log n)O(nlogn) time complexity but
requires additional space for merging.

R C Vikram

You might also like