# sorting.py
import time, random
####################################################
# swap
####################################################
def swap(a, i, j):
(a[i], a[j]) = (a[j], a[i])
####################################################
# selectionSort
####################################################
def selectionSort(a):
n = len(a)
for startIndex in range(n):
minIndex = startIndex
for i in range(startIndex+1, n):
if (a[i] < a[minIndex]):
minIndex = i
swap(a, startIndex, minIndex)
####################################################
# mergeSort
####################################################
def merge(a, 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 (a[index1] > a[index2]))):
aux[i] = a[index2]
index2 += 1
else:
aux[i] = a[index1]
index1 += 1
for i in range(start1, end):
a[i] = aux[i - start1]
def mergeSort(a):
n = len(a)
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(a, start1, start2, end)
step *= 2
####################################################
# builtinSort (wrapped as a function)
####################################################
def builtinSort(a):
a.sort()
####################################################
# testSort
####################################################
def testSort(sortFn, n):
a = [random.randint(0,2**31) for i in range(n)]
sortedA = sorted(a)
startTime = time.time()
sortFn(a)
endTime = time.time()
elapsedTime = endTime - startTime
assert(a == sortedA)
print(f'{sortFn.__name__:>20} n={n}, time={elapsedTime:6.3f}')
def testSorts():
n = 2**8 # use 2**8 for Brython, use 2**12 or larger for Python
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