0% found this document useful (0 votes)
34 views20 pages

Python Data Structures and Algorithms

The document contains various Python implementations for fundamental data structures and algorithms including binary search, bubble sort, queue, stack, linked list, depth-first search (DFS), breadth-first search (BFS), and Dijkstra's algorithm. It also includes methods for merging sorted arrays and checking if a binary tree is balanced. Each section provides example usage and expected output for clarity.

Uploaded by

pomepo2613
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)
34 views20 pages

Python Data Structures and Algorithms

The document contains various Python implementations for fundamental data structures and algorithms including binary search, bubble sort, queue, stack, linked list, depth-first search (DFS), breadth-first search (BFS), and Dijkstra's algorithm. It also includes methods for merging sorted arrays and checking if a binary tree is balanced. Each section provides example usage and expected output for clarity.

Uploaded by

pomepo2613
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

1.

Implement binary search to find the position of a target element in a


sorted array.

def binary_search(arr, target):


# Set the initial low and high pointers
low = 0
high = len(arr) - 1

# Iterate while the low pointer is less than or equal to the high pointer
while low <= high:
# Find the middle index
mid = (low + high) // 2

# If the target element is found, return its index


if arr[mid] == target:
return mid

# If the target is less than the middle element, search the left half
elif arr[mid] > target:
high = mid - 1

# If the target is greater than the middle element, search the right half
else:
low = mid + 1

# If the target element is not found, return -1


return -1

# Example usage:
arr = [1, 3, 5, 7, 9, 11, 13, 15]
target = 7
result = binary_search(arr, target)

if result != -1:
print(f"Element {target} is at index {result}.")
else:
print(f"Element {target} is not in the array.")

O/p:
[1, 3, 5, 7, 9, 11, 13, 15]
2. Write a program to sort a list using the bubble sort algorithm.

def bubble_sort(arr):
n = len(arr)

# Traverse through all elements in the list


for i in range(n):
# Last i elements are already sorted, so no need to check them again
swapped = False # Flag to check if any swap happened

for j in range(0, n-i-1):


# Compare adjacent elements
if arr[j] > arr[j+1]:
# Swap if the element is greater than the next element
arr[j], arr[j+1] = arr[j+1], arr[j]
swapped = True

# If no elements were swapped, the list is already sorted


if not swapped:
break

return arr

# Example usage:
arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = bubble_sort(arr)

print("Sorted array is:", sorted_arr)

O/p:
Sorted array is: [11, 12, 22, 25, 34, 64, 90]
3. Implement a queue using a list in Python.

class Queue:
def __init__(self):
[Link] = [] # Initialize an empty list to store queue elements

def enqueue(self, item):


"""Add an item to the rear of the queue"""
[Link](item)

def dequeue(self):
"""Remove and return the item from the front of the queue"""
if self.is_empty():
return "Queue is empty"
return [Link](0)

def peek(self):
"""Return the item at the front of the queue without removing it"""
if self.is_empty():
return "Queue is empty"
return [Link][0]

def is_empty(self):
"""Check if the queue is empty"""
return len([Link]) == 0

def size(self):
"""Return the number of elements in the queue"""
return len([Link])

# Example usage:
queue = Queue()

# Enqueue elements
[Link](10)
[Link](20)
[Link](30)

# Display the queue after enqueuing elements


print("Queue after enqueuing 10, 20, 30:", [Link])
# Dequeue an element
print("Dequeue operation result:", [Link]()) # Should remove
10
print("Queue after dequeue:", [Link])

# Peek the front element


print("Peek operation result:", [Link]()) # Should show 20

# Check if the queue is empty


print("Is the queue empty?", queue.is_empty()) # Should return False

# Get the size of the queue


print("Queue size:", [Link]()) # Should return 2

O/p:
Queue after enqueuing 10, 20, 30: [10, 20, 30]
Dequeue operation result: 10
Queue after dequeue: [20, 30]
Peek operation result: 20
Is the queue empty? False
Queue size: 2
4. Implement a stack data structure with push, pop, and
display operations.

class Stack:
def __init__(self):
[Link] = [] # Initialize an empty list to store stack elements

def push(self, item):


"""Add an item to the top of the stack"""
[Link](item)

def pop(self):
"""Remove and return the item from the top of the stack"""
if self.is_empty():
return "Stack is empty"
return [Link]()

def display(self):
"""Display the current elements in the stack"""
if self.is_empty():
return "Stack is empty"
return [Link]

def is_empty(self):
"""Check if the stack is empty"""
return len([Link]) == 0

# Example usage:
stack = Stack()

# Push elements onto the stack


[Link](10)
[Link](20)
[Link](30)

# Display the stack after pushing elements


print("Stack after pushing 10, 20, 30:", [Link]())

# Pop an element from the stack


print("Pop operation result:", [Link]()) # Should remove 30
print("Stack after pop:", [Link]())

# Display the stack content


print("Current stack:", [Link]())

# Check if the stack is empty


print("Is the stack empty?", stack.is_empty()) # Should return False

# Pop remaining elements


print("Pop operation result:", [Link]()) # Should remove 20
print("Pop operation result:", [Link]()) # Should remove 10

# Check if the stack is empty now


print("Is the stack empty now?", stack.is_empty()) # Should return True

O/p:
Stack after pushing 10, 20, 30: [10, 20, 30]
Pop operation result: 30
Stack after pop: [10, 20]
Current stack: [10, 20]
Is the stack empty? False
Pop operation result: 20
Pop operation result: 10
Is the stack empty now? True
5. Write a program to merge two sorted arrays into a single
sorted array

def merge_sorted_arrays(arr1, arr2):


# Initialize pointers for both arrays and the result array
i, j = 0, 0
merged_arr = []

# Traverse both arrays and merge them


while i < len(arr1) and j < len(arr2):
if arr1[i] < arr2[j]:
merged_arr.append(arr1[i])
i += 1
else:
merged_arr.append(arr2[j])
j += 1

# If there are remaining elements in arr1, append them


while i < len(arr1):
merged_arr.append(arr1[i])
i += 1

# If there are remaining elements in arr2, append them


while j < len(arr2):
merged_arr.append(arr2[j])
j += 1

return merged_arr

# Example usage:
arr1 = [1, 3, 5, 7]
arr2 = [2, 4, 6, 8]

merged_array = merge_sorted_arrays(arr1, arr2)


print("Merged sorted array:", merged_array)

O/p:
Merged sorted array: [1, 2, 3, 4, 5, 6, 7, 8]
6. Write a program to find the shortest path in a graph using
Dijkstra's algorithm.

import heapq

def dijkstra(graph, start):


# Initialize distances from start to all other nodes as infinity
# and distance to start node as 0
distances = {node: float('inf') for node in graph}
distances[start] = 0

# Priority queue to select the node with the smallest tentative


distance
pq = [(0, start)] # (distance, node)

while pq:
# Get the node with the smallest distance
current_distance, current_node = [Link](pq)

# Skip if we've already found a better way to this node


if current_distance > distances[current_node]:
continue

# Explore the neighbors of the current node


for neighbor, weight in graph[current_node].items():
distance = current_distance + weight

# If the newly calculated distance is shorter, update it


if distance < distances[neighbor]:
distances[neighbor] = distance
[Link](pq, (distance, neighbor))

return distances

# Example graph
graph = {
'A': {'B': 1, 'C': 4},
'B': {'A': 1, 'C': 2, 'D': 5},
'C': {'A': 4, 'B': 2, 'D': 1},
'D': {'B': 5, 'C': 1}
}

# Start from node 'A'


start_node = 'A'
shortest_paths = dijkstra(graph, start_node)

# Print shortest distances from the start node to all other nodes
print("Shortest paths from node", start_node)
for node, distance in shortest_paths.items():
print(f"Distance from {start_node} to {node} is {distance}")

O/p:

Shortest paths from node A


Distance from A to A is 0
Distance from A to B is 1
Distance from A to C is 3
Distance from A to D is 4
7. Implement a linked list with insertion and deletion operations.

class Node:
def __init__(self, data):
[Link] = data # The value of the node
[Link] = None # Pointer to the next node

class LinkedList:
def __init__(self):
[Link] = None # Initially, the list is empty

# Insert at the end of the list


def insert_end(self, data):
new_node = Node(data)
if [Link] is None:
[Link] = new_node # If the list is empty, new node becomes
the head
return
last = [Link]
while [Link]:
last = [Link]
[Link] = new_node

# Insert at the beginning of the list


def insert_begin(self, data):
new_node = Node(data)
new_node.next = [Link]
[Link] = new_node

# Delete a node with a specific value


def delete_node(self, key):
temp = [Link]

# If the node to be deleted is the head node


if temp is not None and [Link] == key:
[Link] = [Link]
temp = None
return

# Search for the node to be deleted


prev = None
while temp is not None and [Link] != key:
prev = temp
temp = [Link]

# If the key was not found


if temp is None:
print(f"Node with value {key} not found.")
return

# Unlink the node from the linked list


[Link] = [Link]
temp = None

# Print the linked list


def display(self):
if [Link] is None:
print("List is empty.")
return
current = [Link]
while current:
print([Link], end=" -> ")
current = [Link]
print("None")

# Example usage
linked_list = LinkedList()

# Insert elements
linked_list.insert_end(10)
linked_list.insert_end(20)
linked_list.insert_end(30)

print("Linked List after insertion at the end:")


linked_list.display()

linked_list.insert_begin(5)

print("Linked List after insertion at the beginning:")


linked_list.display()
# Delete a node with value 20
linked_list.delete_node(20)

print("Linked List after deleting node with value 20:")


linked_list.display()

# Delete a node that does not exist


linked_list.delete_node(50)

O/p:
Linked List after insertion at the end:
10 -> 20 -> 30 -> None
Linked List after insertion at the beginning:
5 -> 10 -> 20 -> 30 -> None
Linked List after deleting node with value 20:
5 -> 10 -> 30 -> None
Node with value 50 not found.
8. Write a program to perform depth-first search (DFS) on a
graph.

class Graph:
def __init__(self):
[Link] = {} # Dictionary to store graph as an adjacency list

def add_edge(self, u, v):


"""Add an edge from vertex u to vertex v"""
if u not in [Link]:
[Link][u] = []
if v not in [Link]:
[Link][v] = []
[Link][u].append(v)
[Link][v].append(u) # For undirected graph, add edge in both
directions

def dfs(self, start):


"""Perform DFS starting from vertex 'start'"""
visited = set() # Set to track visited vertices
self._dfs_helper(start, visited)

def _dfs_helper(self, vertex, visited):


"""Helper function to perform DFS using recursion"""
[Link](vertex)
print(vertex, end=" ")

for neighbor in [Link][vertex]:


if neighbor not in visited:
self._dfs_helper(neighbor, visited)

# Example usage:
graph = Graph()

# Adding edges to the graph


graph.add_edge('A', 'B')
graph.add_edge('A', 'C')
graph.add_edge('B', 'D')
graph.add_edge('B', 'E')
graph.add_edge('C', 'F')

print("DFS traversal starting from vertex A:")


[Link]('A')

O/p:
DFS traversal starting from vertex A:
ABDECF
9. Write a program to perform breadth-first search (BFS) on a
graph.

from collections import deque

class Graph:
def __init__(self):
[Link] = {} # Dictionary to store graph as an adjacency list

def add_edge(self, u, v):


"""Add an edge from vertex u to vertex v"""
if u not in [Link]:
[Link][u] = []
if v not in [Link]:
[Link][v] = []
[Link][u].append(v)
[Link][v].append(u) # For undirected graph, add edge in both
directions

def bfs(self, start):


"""Perform BFS starting from vertex 'start'"""
visited = set() # Set to track visited vertices
queue = deque([start]) # Queue to manage the BFS order
[Link](start)

while queue:
vertex = [Link]()
print(vertex, end=" ")

# Visit all unvisited neighbors of the current vertex


for neighbor in [Link][vertex]:
if neighbor not in visited:
[Link](neighbor)
[Link](neighbor)

# Example usage:
graph = Graph()

# Adding edges to the graph


graph.add_edge('A', 'B')
graph.add_edge('A', 'C')
graph.add_edge('B', 'D')
graph.add_edge('B', 'E')
graph.add_edge('C', 'F')

print("BFS traversal starting from vertex A:")


[Link]('A')

O/p:

BFS traversal starting from vertex A:


ABCDEF

10. Write a program to determine if a binary tree is balanced.

class Node:
def __init__(self, data):
[Link] = data # Node value
[Link] = None # Left child
[Link] = None # Right child

class BinaryTree:
def __init__(self):
[Link] = None # Initially, the tree is empty

def is_balanced(self):
"""Return True if the tree is balanced, False otherwise."""
def check_balance(root):
# If the node is None, return height as 0
if root is None:
return 0

# Recursively find the height of the left subtree


left_height = check_balance([Link])
if left_height == -1:
return -1 # Left subtree is not balanced
# Recursively find the height of the right subtree
right_height = check_balance([Link])
if right_height == -1:
return -1 # Right subtree is not balanced

# If the current node is unbalanced, return -1


if abs(left_height - right_height) > 1:
return -1

# Return the height of the current node


return max(left_height, right_height) + 1

# Start checking balance from the root


return check_balance([Link]) != -1

def insert(self, data):


"""Insert a node with 'data' into the binary tree."""
if [Link] is None:
[Link] = Node(data)
else:
self._insert_recursive([Link], data)

def _insert_recursive(self, node, data):


"""Helper method to insert a node recursively."""
if data < [Link]:
if [Link] is None:
[Link] = Node(data)
else:
self._insert_recursive([Link], data)
else:
if [Link] is None:
[Link] = Node(data)
else:
self._insert_recursive([Link], data)

# Example usage:
bt = BinaryTree()

# Inserting nodes into the binary tree


[Link](10)
[Link](5)
[Link](15)
[Link](3)
[Link](7)
[Link](12)
[Link](18)

print("Is the binary tree balanced?", bt.is_balanced())

# Insert a node that will unbalance the tree


[Link](2)

print("Is the binary tree balanced after adding a new node?",


bt.is_balanced())

O/p:
Is the binary tree balanced? True
Is the binary tree balanced after adding a new node? False

You might also like