bubble sort
swap adjacent elements to bubble up largest element in arr[0:n-i]
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
n passes, (n-1)/2 comparisons per pass, so we have
selection sort
swap current item and min of arr[i:n]
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_idx = i
for j in range(i + 1, n):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
return arr
n passes, (n-1)/2 comparisons per pass, so we have
insertion sort
compare current with items to its left, insert into its correct position from 1 to n
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i] # num to be inserted
j = i - 1
# loop through arr[0:i]
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j] # shift right
j -= 1
arr[j + 1] = key # insert
return arr
again
merge sort
divide and conquer - recursively sort halves before merging them
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
L = arr[:mid]
R = arr[mid:]
merge_sort(L)
merge_sort(R)
# merge sorted subarrays
i = 0 # to traverse L
j = 0 # to traverse R
k = 0 # to traverse arr
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
# add the leftovers
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
return arr
O(n log n):
- O(log n) to divide into log n levels
- O(n) to merge each level
quick sort
divide and conquer - choose a pivot as partition and recursively sort the subarrays
A simplified implementation:
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)