I implemented this version of quicksort by taking the median of 3 elements as the pivot:
def rearrange_array(array, begin_index, end_index):
# choose 3 random indexes in the array
index1 = randint(begin_index, int(begin_index + (end_index - begin_index)/3))
index2 = randint(int(begin_index + (end_index - begin_index)/3), int(begin_index + 2*(end_index - begin_index)/3))
index3 = randint(int(begin_index + 2*(end_index - begin_index)/3), end_index)
if array[index1] > array[index2]:
tmp = array[index1]
array[index1] = array[index2]
array[index2] = tmp
if array[index2] > array[index3]:
tmp = array[index2]
array[index2] = array[index3]
array[index3] = tmp
if array[index1] > array[index2]:
tmp = array[index1]
array[index1] = array[index2]
array[index2] = tmp
# swap index2 and begin_index
tmp = array[index2]
array[index2] = array[end_index]
array[end_index] = tmp
def partition(array, start_index, end_index): # partition = conquer
rearrange_array(array, start_index, end_index)
pivot = array[end_index] # pivot is always the right most index
i = start_index - 1
# if an element is samller than pivot swap it in front
for j in range(start_index, end_index):
if array[j] <= pivot:
i += 1
# swap
tmp = array[i]
array[i] = array[j]
array[j] = tmp
# swap the pivot with the element after i
# since i only goes forward once something smaller than the pivot is found, we know that
# everything in front of i+1 will be smaller than pivot
tmp = array[i+1]
array[i+1] = array[end_index]
array[end_index] = tmp
return i + 1
def quicksort_recursive(array, start_index, end_index):
if start_index < end_index:
pivot_index = partition(array, start_index, end_index)
quicksort_recursive(array, start_index, pivot_index - 1)
quicksort_recursive(array, pivot_index, end_index)
to test the sorting algorithm, I used it on an array of 100k elements which took ~16 seconds
def get_array(length, maximum):
array = []
for _ in range(length):
array.append(randint(0, maximum))
return array
sys.setrecursionlimit(sys.getrecursionlimit() * 100)
a = get_array(100000, 100)
t = time()
quicksort_recursive(a, 0, len(a) - 1)
print(time() - t)
Then I compared it to this version of quicksort, which only took about 0.8-1 second:
def merge(array, left, right):
# the program will only get here once we call mergesort on
# a one element array
i = j = k = 0
# put the smallest one in the array
while i < len(left) and j < len(right):
if left[i] < right[j]:
array[k] = left[i]
i += 1
else:
array[k] = right[j]
j += 1
k += 1
# if one array still has stuff left:
while i < len(left):
array[k] = left[i]
i += 1
k += 1
while j < len(right):
array[k] = right[j]
j += 1
k += 1
def mergesort_recursive(array):
# 1. devide the array in 2
if len(array) > 1:
# divide
middle_index = int(len(array)/2)
left = array[:middle_index]
right = array[middle_index:]
# conquer
mergesort_recursive(left)
mergesort_recursive(right)
# merge
merge(array, left, right)
I'm a bit confused about this, isn't quicksort supposed to be faster than mergesort? I've tried it on an array of 100 elements and it does put the elements in correct order so I'm not sure what's going on
Thanks!