Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions Exercise_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,27 @@
def binarySearch(arr, l, r, x):

#write your code here
while l<=r:
mid = (l+r)//2
if arr[mid] == x:
return mid
elif x>arr[mid]:
l = mid + 1
else:
r = mid -1
return -1




# Test array
arr = [ 2, 3, 4, 10, 40 ]
x = 10
x = 40

# Function call
result = binarySearch(arr, 0, len(arr)-1, x)

if result != -1:
print "Element is present at index % d" % result
print(f"Element is present at index {result}")
else:
print "Element is not present in array"
print("Element is not present in array")
28 changes: 22 additions & 6 deletions Exercise_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,38 @@

# give you explanation for the approach
def partition(arr,low,high):

i = ( low-1 ) # index of smaller element
pivot = arr[high] # pivot

for j in range(low , high):
# If current element is smaller than or
# equal to pivot
if arr[j] <= pivot:
# increment index of smaller element
i = i+1
arr[i],arr[j] = arr[j],arr[i]

#write your code here
arr[i+1],arr[high] = arr[high],arr[i+1]
return ( i+1 )


# Function to do Quick sort
def quickSort(arr,low,high):

#write your code here
if low < high:
# pi is partitioning index, arr[p] is now
# at right place
pi = partition(arr,low,high)

# Separately sort elements before
# partition and after partition
quickSort(arr, low, pi-1)
quickSort(arr, pi+1, high)

# Driver code to test above
arr = [10, 7, 8, 9, 1, 5]
n = len(arr)
quickSort(arr,0,n-1)
print ("Sorted array is:")
for i in range(n):
print ("%d" %arr[i]),


print ("%d" %arr[i]),
18 changes: 16 additions & 2 deletions Exercise_3.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,33 @@
class Node:

# Function to initialise the node object
def __init__(self, data):
def __init__(self, data):
self.data = data
self.next = None

class LinkedList:

def __init__(self):
self.head = None


def push(self, new_data):
new_node = Node(new_data)
new_node.next = self.head
self.head = new_node


# Function to get the middle of
# the linked list
def printMiddle(self):
def printMiddle(self):
slow_ptr = self.head
fast_ptr = self.head

if self.head is not None:
while (fast_ptr is not None and fast_ptr.next is not None):
fast_ptr = fast_ptr.next.next
slow_ptr = slow_ptr.next
print("The middle element is:", slow_ptr.data)

# Driver code
list1 = LinkedList()
Expand Down
52 changes: 43 additions & 9 deletions Exercise_4.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,52 @@
# Python program for implementation of MergeSort
def mergeSort(arr):

#write your code here
if len(arr) > 1:
mid = len(arr)//2 #Finding the mid of the array
L = arr[:mid] # Dividing the elements into 2 halves
R = arr[mid:]

# Sorting the first half
mergeSort(L)

# Sorting the second half
mergeSort(R)

i = j = k = 0

# Copy data to temp arrays L[] and R[]
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

# Checking if any element was left
while i < len(L):
arr[k] = L[i]
i += 1
k += 1

while j < len(R):
arr[k] = R[j]
j += 1
k += 1

#write your code here

# Code to print the list
def printList(arr):
def printList(arr):
print(arr)

#write your code here

# driver code to test the above code
if __name__ == '__main__':
arr = [12, 11, 13, 5, 6, 7]
print ("Given array is", end="\n")
printList(arr)
mergeSort(arr)
print("Sorted array is: ", end="\n")
printList(arr)
arr = [12, 11, 13, 5, 6, 7]
print ("Given array is", end="\n")
printList(arr)
mergeSort(arr)
print("Sorted array is: ", end="\n")
printList(arr)
143 changes: 141 additions & 2 deletions Exercise_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,148 @@

# This function is same in both iterative and recursive
def partition(arr, l, h):
#write your code here
"""
Partition function using Lomuto partition scheme.
Takes last element as pivot, places the pivot element at its correct
position in sorted array, and places all smaller elements to left
of pivot and all greater elements to right of pivot.

Time Complexity: O(n)
Space Complexity: O(1)
"""
# Choose the rightmost element as pivot
pivot = arr[h]

# Index of smaller element indicates the right position of pivot found so far
i = l - 1

for j in range(l, h):
# If current element is smaller than or equal to pivot
if arr[j] <= pivot:
i += 1 # increment index of smaller element
arr[i], arr[j] = arr[j], arr[i] # swap elements

# Place pivot at correct position
arr[i + 1], arr[h] = arr[h], arr[i + 1]
return i + 1 # return position of pivot


def quickSortIterative(arr, l, h):
#write your code here
"""
Iterative implementation of QuickSort using only a stack.

Time Complexity:
- Best/Average Case: O(n log n)
- Worst Case: O(n²)
Space Complexity: O(log n) for stack space
"""
# Create a stack to store pairs of (low, high) indices
stack = []

# Push initial values of l and h to stack as a tuple
stack.append((l, h))

# Keep processing while stack is not empty
while stack:
# Pop low and high indices from stack
low, high = stack.pop()

# Only process if there are at least 2 elements
if low < high:
# Partition the array and get pivot index
pivot_index = partition(arr, low, high)

# Push left subarray to stack (if it has more than 1 element)
if pivot_index - 1 > low:
stack.append((low, pivot_index - 1))

# Push right subarray to stack (if it has more than 1 element)
if pivot_index + 1 < high:
stack.append((pivot_index + 1, high))


def quickSortRecursive(arr, l, h):
"""
Recursive implementation of QuickSort.

Time Complexity:
- Best/Average Case: O(n log n)
- Worst Case: O(n²)
Space Complexity: O(log n) for recursion stack
"""
if l < h:
# Partition the array and get pivot index
pi = partition(arr, l, h)

# Recursively sort elements before and after partition
quickSortRecursive(arr, l, pi - 1)
quickSortRecursive(arr, pi + 1, h)


def print_array(arr):
"""Helper function to print array"""
print(" ".join(map(str, arr)))


# Test the implementation
if __name__ == "__main__":
# Test case 1: Random array
print("=== QuickSort Implementation Test ===")

arr1 = [64, 34, 25, 12, 22, 11, 90]
print(f"Original array: {arr1}")

# Test iterative quicksort
arr1_copy = arr1.copy()
quickSortIterative(arr1_copy, 0, len(arr1_copy) - 1)
print(f"Sorted (Iterative): {arr1_copy}")

# Test recursive quicksort
arr1_copy2 = arr1.copy()
quickSortRecursive(arr1_copy2, 0, len(arr1_copy2) - 1)
print(f"Sorted (Recursive): {arr1_copy2}")

print()

# Test case 2: Already sorted array
arr2 = [1, 2, 3, 4, 5]
print(f"Already sorted array: {arr2}")
arr2_copy = arr2.copy()
quickSortIterative(arr2_copy, 0, len(arr2_copy) - 1)
print(f"After quicksort: {arr2_copy}")

print()

# Test case 3: Reverse sorted array
arr3 = [5, 4, 3, 2, 1]
print(f"Reverse sorted array: {arr3}")
arr3_copy = arr3.copy()
quickSortRecursive(arr3_copy, 0, len(arr3_copy) - 1)
print(f"After quicksort: {arr3_copy}")

print()

# Test case 4: Array with duplicates
arr4 = [3, 6, 8, 10, 1, 2, 1]
print(f"Array with duplicates: {arr4}")
arr4_copy = arr4.copy()
quickSortIterative(arr4_copy, 0, len(arr4_copy) - 1)
print(f"After quicksort: {arr4_copy}")

print()

# Test case 5: Single element
arr5 = [42]
print(f"Single element array: {arr5}")
arr5_copy = arr5.copy()
quickSortRecursive(arr5_copy, 0, len(arr5_copy) - 1)
print(f"After quicksort: {arr5_copy}")

print()

# Test case 6: Empty array
arr6 = []
print(f"Empty array: {arr6}")
if arr6: # Only sort if array is not empty
quickSortIterative(arr6, 0, len(arr6) - 1)
print(f"After quicksort: {arr6}")