Assignment 3: Sorting, Stacks, Queues, and Linked Lists
1. Sorting Algorithms with Timing
import time
import random
def bubble_sort(arr):
for i in range(len(arr)):
for j in range(0, len(arr) - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and key < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr)//2
L = arr[:mid]
R = arr[mid:]
merge_sort(L)
merge_sort(R)
i = j = k = 0
while i < len(L) and j < len(R):
if L[i] < R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[0]
left = [x for x in arr[1:] if x < pivot]
right = [x for x in arr[1:] if x >= pivot]
return quick_sort(left) + [pivot] + quick_sort(right)
sizes = [100, 1000, 10000]
for size in sizes:
print(f"\nSorting {size} elements")
data = [random.randint(0, size) for _ in range(size)]
for sort_func in [bubble_sort, insertion_sort, merge_sort]:
arr_copy = data.copy()
start = time.time()
sort_func(arr_copy)
end = time.time()
print(f"{sort_func.__name__} took {end - start:.4f} seconds")
if size <= 10000: # quick sort returns a new array
start = time.time()
sorted_arr = quick_sort(data.copy())
end = time.time()
print(f"quick_sort took {end - start:.4f} seconds")
2. Stack and Queue using Arrays and Linked Lists
# Stack using array
class StackArray:
def __init__(self):
self.stack = []
def push(self, val):
self.stack.append(val)
def pop(self):
return self.stack.pop() if self.stack else None
def top(self):
return self.stack[-1] if self.stack else None
# Queue using array
class QueueArray:
def __init__(self):
self.queue = []
def enqueue(self, val):
self.queue.append(val)
def dequeue(self):
return self.queue.pop(0) if self.queue else None
# Stack and Queue using linked list
class Node:
def __init__(self, data):
self.data = data
self.next = None
class StackLinkedList:
def __init__(self):
self.head = None
def push(self, val):
new_node = Node(val)
new_node.next = self.head
self.head = new_node
def pop(self):
if not self.head: return None
val = self.head.data
self.head = self.head.next
return val
class QueueLinkedList:
def __init__(self):
self.front = self.rear = None
def enqueue(self, val):
new_node = Node(val)
if not self.rear:
self.front = self.rear = new_node
return
self.rear.next = new_node
self.rear = new_node
def dequeue(self):
if not self.front: return None
val = self.front.data
self.front = self.front.next
if not self.front:
self.rear = None
return val
3. Singly Linked List Operations
class Node:
def __init__(self, data):
self.data = data
self.next = None
class LinkedList:
def __init__(self):
self.head = None
def insert_beginning(self, data):
new_node = Node(data)
new_node.next = self.head
self.head = new_node
def insert_end(self, data):
new_node = Node(data)
if not self.head:
self.head = new_node
return
temp = self.head
while temp.next:
temp = temp.next
temp.next = new_node
def insert_position(self, data, pos):
new_node = Node(data)
if pos == 0:
self.insert_beginning(data)
return
temp = self.head
for _ in range(pos-1):
if not temp:
return
temp = temp.next
new_node.next = temp.next
temp.next = new_node
def delete_node(self, key):
temp = self.head
if temp and temp.data == key:
self.head = temp.next
return
while temp.next and temp.next.data != key:
temp = temp.next
if temp.next:
temp.next = temp.next.next
def update_node(self, old_val, new_val):
temp = self.head
while temp:
if temp.data == old_val:
temp.data = new_val
return
temp = temp.next
def search(self, key):
temp = self.head
while temp:
if temp.data == key:
return True
temp = temp.next
return False
def display(self):
temp = self.head
while temp:
print(temp.data, end=" -> ")
temp = temp.next
print("None")
def reverse(self):
prev = None
current = self.head
while current:
nxt = current.next
current.next = prev
prev = current
current = nxt
self.head = prev
def sort(self):
vals = []
temp = self.head
while temp:
vals.append(temp.data)
temp = temp.next
vals.sort()
temp = self.head
for val in vals:
temp.data = val
temp = temp.next