bubble sort, merge sort, heap sort and quick sort
from functools import wraps
from time import time
import numpy as np
size = 100000
print('size = {}\n'.format(size))
def timing(func):
@wraps(func)
def wrapper(*args, **kwargs):
a = np.random.randint(size, size=size)
print('Function {} was called'.format(func.__name__))
start = time()
result = func(a)
end = time()
print('Elapsed time: {:.3f} s\n'.format(end-start))
return result
return wrapper
# bubble sort
@timing
def bubble_sort(arr: 'array') -> 'the sorted array':
n = len(arr)
for i in range(n - 1):
for j in range(n - (i+1)):
if arr[j] > arr[j+1]:
arr[j], arr[j+1] = arr[j+1], arr[j]
return arr
# merge sort
def merge(left, right):
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
def merge_sort(arr):
n = len(arr)
if n <= 1:
return arr
middle = int(n/2)
left = merge_sort(arr[:middle])
right = merge_sort(arr[middle:])
return merge(left, right)
def in_place_merge(arr, left, middle, right):
i, j = left, middle+1
while i <= middle and j <= right:
if arr[i] <= arr[j]:
i += 1
else:
temp = arr[j]
arr[i+1:j+1] = arr[i:j] # shift part of the array
arr[i] = temp
i += 1
j += 1
middle += 1
def in_place_merge_sort(arr, left, right):
if left < right:
middle = int((left+right) / 2)
in_place_merge_sort(arr, left, middle)
in_place_merge_sort(arr, middle+1, right)
in_place_merge(arr, left, middle, right)
# heap sort
def max_heapify(arr, node: 'in [0, ..., n-1]', heap_size):
left = 2*node + 1
right = left + 1
largest = node
if left <= heap_size-1 and arr[left] > arr[node]:
largest = left
if right <= heap_size-1 and arr[right] > arr[largest]:
largest = right
if largest != node:
arr[node], arr[largest] = arr[largest], arr[node]
max_heapify(arr, largest, heap_size)
def build_max_heap(arr):
n = len(arr)
for node in range(int(n/2)-1, -1, -1):
max_heapify(arr, node, n)
def heap_sort(arr):
build_max_heap(arr)
heap_size = len(arr)
for node in range(len(arr)-1, 0, -1):
arr[0], arr[node] = arr[node], arr[0]
heap_size -= 1
max_heapify(arr, 0, heap_size)
# quick sort
import sys
sys.setrecursionlimit(size)
def partition(arr, left, right):
pivot = arr[right]
i = left - 1
for j in range(left, right):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i+2:right+1] = arr[i+1:right]
arr[i+1] = pivot
return i + 1
def quick_sort(arr, left, right):
if left < right:
p_index = partition(arr, left, right)
quick_sort(arr, left, p_index-1)
quick_sort(arr, p_index+1, right)
def randomized_partition(arr, left, right):
index = np.random.randint(left, right)
arr[index], arr[right] = arr[right], arr[index]
# the only difference is above two lines
pivot = arr[right]
i = left - 1
for j in range(left, right):
if arr[j] <= pivot:
i += 1
arr[i], arr[j] = arr[j], arr[i]
arr[i+2:right+1] = arr[i+1:right]
arr[i+1] = pivot
return i + 1
def randomized_quick_sort(arr, left, right):
if left < right:
p_index = randomized_partition(arr, left, right)
quick_sort(arr, left, p_index-1)
quick_sort(arr, p_index+1, right)
bubble_sort()
def test(func, *args, **kwargs):
a = np.random.randint(size, size=size)
print('Function {} was called'.format(func.__name__))
start = time()
func(a, *args, **kwargs)
end = time()
print('Elapsed time: {:.3f} s\n'.format(end-start))
test(merge_sort)
test(in_place_merge_sort, left=0, right=size-1)
test(heap_sort)
test(quick_sort, left=0, right=size-1)
test(randomized_quick_sort, left=0, right=size-1)