# sorting.py
import time, random, sys
####################################################
# swap
####################################################
def swap(L, i, j):
L[i], L[j] = L[j], L[i]
####################################################
# selectionSort
####################################################
def selectionSort(L):
n = len(L)
for startIndex in range(n):
minIndex = startIndex
for i in range(startIndex+1, n):
if L[i] < L[minIndex]:
minIndex = i
swap(L, startIndex, minIndex)
####################################################
# mergeSort
####################################################
def merge(L, start1, start2, end):
index1 = start1
index2 = start2
length = end - start1
aux = [None] * length
for i in range(length):
if ((index1 == start2) or
((index2 != end) and (L[index1] > L[index2]))):
aux[i] = L[index2]
index2 += 1
else:
aux[i] = L[index1]
index1 += 1
for i in range(start1, end):
L[i] = aux[i - start1]
def mergeSort(L):
n = len(L)
step = 1
while (step < n):
for start1 in range(0, n, 2*step):
start2 = min(start1 + step, n)
end = min(start1 + 2*step, n)
merge(L, start1, start2, end)
step *= 2
####################################################
# builtinSort (wrapped as a function)
####################################################
def builtinSort(L):
L.sort()
####################################################
# testSort
####################################################
def testSort(sortFn, n):
L = [random.randint(0,2**31) for i in range(n)]
sortedL = sorted(L)
startTime = time.time()
sortFn(L)
endTime = time.time()
elapsedTime = endTime - startTime
assert(L == sortedL)
print(f'{sortFn.__name__:>20} n={n}, time={elapsedTime:6.3f}')
def testSorts():
if sys.platform == 'brython':
sizes = [2**9, 2**10]
else:
sizes = [2**12, 2**13, 2**14]
for n in sizes:
print(f'Testing sorts for n = {n}:')
for sortFn in [selectionSort, mergeSort, builtinSort]:
testSort(sortFn, n)
testSorts()
# The following functions all solve the same problem:
# Given a non-negative integer n, return True if n is the sum
# of the squares of two non-negative integers, and False otherwise.
def f1(n):
for x in range(n+1):
for y in range(n+1):
if (x**2 + y**2 == n):
return True
return False
def f2(n):
for x in range(n+1):
for y in range(x,n+1):
if (x**2 + y**2 == n):
return True
return False
def f3(n):
xmax = int(n**0.5)
for x in range(xmax+1):
for y in range(x,n+1):
if (x**2 + y**2 == n):
return True
return False
def f4(n):
xyMax = int(n**0.5)
for x in range(xyMax+1):
for y in range(x,xyMax+1):
if (x**2 + y**2 == n):
return True
return False
def f5(n):
xyMax = int(n**0.5)
for x in range(xyMax+1):
y = int((n - x**2)**0.5)
if (x**2 + y**2 == n):
return True
return False
def testFunctionsMatch(maxToCheck):
# first, verify that all 5 functions work the same
print("Verifying that all functions work the same...")
for n in range(maxToCheck):
assert(f1(n) == f2(n) == f3(n) == f4(n) == f5(n))
print("All functions match up to n =", maxToCheck)
testFunctionsMatch(100) # use larger number to be more confident
import time
def timeFnCall(f, n):
# call f(n) and return time in ms
# Actually, since one call may require less than 1 ms,
# we'll keep calling until we get at least 1 secs,
# then divide by # of calls we had to make
calls = 0
start = end = time.time()
while (end - start < 1):
f(n)
calls += 1
end = time.time()
return float(end - start)/calls*1000 #(convert to ms)
def timeFnCalls(n):
print("***************")
for f in [f1, f2, f3, f4, f5]:
print(f'{f.__name__}({n}) takes {timeFnCall(f, n):8.3f} milliseconds')
timeFnCalls(1001) # use larger number, say 3000, to get more accurate timing