Implement Merge and quick sorting algorithms compute space and time complexities
Description
Quick Sort: Efficient divide-and-conquer algorithm with O(n log n) average and worst-case time complexity for sorting large datasets. Merge Sort: Effective divide-and-conquer algorithm with O(n log n) average and worst-case time complexity for sorting large datasets by recursively dividing, sorting, and merging sub-lists.
Merge Sort
Code
program4b-merge-sort.py
def mergeSort(arr):
if len(arr) > 1:
a = len(arr) //2
l = arr[:a]
r = arr[a:]
# sort the two halves
mergeSort(l)
mergeSort(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
import time
import numpy as np
import matplotlib.pyplot as plt
elements = np.array([i*1000 for i in range(1, 5)])
plt.xlabel('List Length')
plt.ylabel('Time Complexity')
times = list()
start_all = time.time()
for i in range(1, 5):
start = time.time()
a = np.random.randint(1000, size=i*1000)
mergeSort(a)
end = time.time()
times.append(end - start)
print("Merge Sort Sorted", i*1000, "Elements in", end - start, "s")
end_all = time.time()
print("Merge Sort Sorted Elements in", end_all - start_all, "s")
plt.plot(elements, times, label="Merge Sort")
plt.grid()
plt.legend()
plt.show()
Output
Explanation of above code
Introduction
- The Merge Sort algorithm is a divide-and-conquer algorithm that recursively divides the input list into smaller sublists until each sublist contains only one element.
- It then merges these sublists in a sorted manner until a single sorted list is obtained.
Code Explanation
- Divide:
- The input list is divided into two halves, approximately of equal size.
- Conquer:
- Recursively sort the two halves by applying the Merge Sort algorithm.
- Merge:
- Merge the two sorted halves into a single sorted list by comparing and merging the elements.
- Code Implementation
- The code starts by defining the mergeSort function, which performs the Merge Sort algorithm on an input array.
- It recursively divides the array into smaller subarrays and then merges them to obtain the final sorted array.
- The code also includes a section for the full code implementation, which measures the time complexity of the Merge Sort algorithm for sorting different-sized lists of elements.
- Initialization:
- The code initializes an empty list (times) to store the execution times for different list lengths.
- It also creates a range of list lengths (elements) for which the time complexity will be measured.
- Loop:
- The code loops over each list length in the elements range.
- Sorting and Timing:
- For each list length, the code generates a random list of integers using NumPy's random.randint() function.
- It then applies the mergeSort function to sort the list and measures the execution time using the time.time() function.
- The execution time is appended to the times list.
- Printing and Plotting:
- After sorting each list length, the code prints the number of elements and the corresponding execution time.
- Finally, it plots the list lengths (elements) on the x-axis and the execution times (times) on the y-axis using Matplotlib, with the label "Merge Sort" for the legend.
Conclusion
- The given code demonstrates the implementation of the Merge Sort algorithm and measures its time complexity for sorting different-sized lists of elements.
- The execution times are recorded and plotted, allowing for an analysis of the algorithm's performance as the list length increases.
- Merge Sort has an average and worst-case time complexity of O(n log n), making it an efficient sorting algorithm for large datasets.
Learn more
Quick Sort
Code
program4b-quick-sort.py
def partition(tempList, low, high):
i = low - 1
pivot = tempList[high]
for j in range(low, high):
if tempList[j] < pivot:
i+=1
tempList[i],tempList[j] = tempList[j],tempList[i]
tempList[i+1],tempList[high] = tempList[high],tempList[i+1]
return(i+1)
def quickSort(tempList, low, high):
if low < high:
pi = partition(tempList, low, high)
quickSort(tempList, low, pi -1)
quickSort(tempList,pi+1, high)
# --------------------------------------------------
import time
import numpy as np
import matplotlib.pyplot as plt
elements = np.array([i*1000 for i in range(1, 10)])
plt.xlabel('List Length')
plt.ylabel('Time Complexity')
times = list()
start_all = time.time()
for i in range(1, 10):
start = time.time()
a = np.random.randint(1000, size=i*1000)
quickSort(a,0,len(a)-1)
end = time.time()
times.append(end - start)
print("Quick Sort Sorted", i*1000, "Elements in", end - start, "s")
end_all = time.time()
print("Quick Sort Sorted Elements in", end_all - start_all, "s")
plt.plot(elements, times, label="Quick Sort")
plt.grid()
plt.legend()
plt.show()
Output
Explanation of above code
Introduction
- The Quick Sort algorithm is a divide-and-conquer algorithm that works by selecting a pivot element and partitioning the other elements into two sub-arrays, according to whether they are less than or greater than the pivot.
- The sub-arrays are then recursively sorted.
Code Explanation
- Choose a pivot:
- Select an element from the array as the pivot element.
- Partition:
- Rearrange the array in such a way that all elements smaller than the pivot are placed before it, and all elements greater than the pivot are placed after it.
- The pivot element will be in its final sorted position.
- Recursively sort sub-arrays:
- Apply the Quick Sort algorithm recursively to the sub-array on the left of the pivot and the sub-array on the right of the pivot.
Code Implementation
- The code starts by defining two functions: partition and quickSort.
- The partition function performs the partitioning process.
- It selects the last element as the pivot and rearranges the elements accordingly.
- It returns the index of the pivot element.
- The quickSort function serves as the main function for implementing the Quick Sort algorithm.
- It recursively applies the quickSort function to the sub-arrays on the left and right of the pivot.
- After defining the functions, the code includes a section for the full code implementation.
- Initialization:
- The code initializes an empty list (times) to store the execution times for different list lengths.
- It also creates a range of list lengths (elements) for which the time complexity will be measured.
- Loop:
- The code loops over each list length in the elements range.
- Sorting and Timing:
- For each list length, the code generates a random list of integers and applies the quickSort function to sort the list.
- It measures the execution time and appends it to the times list.
- Printing and Plotting:
- After sorting each list length, the code prints the number of elements and the corresponding execution time.
- Finally, it plots the list lengths on the x-axis and the execution times on the y-axis, with the label "Quick Sort" for the legend.
Conclusion
- The given code demonstrates the implementation of the Quick Sort algorithm and measures its time complexity for sorting different-sized lists of elements.
- The execution times are recorded and plotted, allowing for an analysis of the algorithm's performance as the list length increases.
- Quick Sort has an average time complexity of O(n log n) and a worst-case time complexity of O(n^2), but it is generally considered efficient and widely used for sorting large datasets.