In [ ]:
%%HTML
<style>.container { width:100% }
</style>
As radix sort is based on counting sort, we have to start our implementation of radix sort by defining the function countingSort
that we have already discussed previously. The easiest way to do this is by using the %run
magic that Juypter notebooks provide.
In [ ]:
%run Counting-Sort.ipynb
The function $\texttt{extractByte}(n, k)$ takes a natural number $n < 2^{32}$ and a number $k\in \{1,2,3,4\}$ as arguments. It returns the $k$-th byte of $n$.
In [ ]:
def extractByte(n, k):
return n >> (8 * (k-1)) & 255
In [ ]:
n = 123456789
B = [extractByte(n, k) for k in [1, 2, 3, 4]]
assert n == sum([B[k] * 256 ** k for k in [0, 1, 2, 3]])
The function $\texttt{radixSort}(L)$ sorts a list $L$ of unsigned 32 bit integers and returns the sorted list. The idea is to sort these numbers by first sorting them with respect to their last byte, then to sort the list with respect to the second byte, then with respect to the third byte, and finally with respect to the most important byte. These four sorts are done using counting sort. The fact that counting sort is stable guarantees that when we sort with respect to the second byte, numbers that have the same second byte will still be sorted with respect to the first byte.
In [ ]:
def radixSort(L):
for k in range(1, 4+1):
Grades = [extractByte(n, k) for n in L]
L = countingSort(L, Grades)[0]
return L
In [ ]:
import random as rnd
In [ ]:
def demo():
L = [ rnd.randrange(1, 1000) for n in range(1, 16) ]
print("L = ", L)
S = radixSort(L)
print("S = ", S)
In [ ]:
demo()
In [ ]:
def isOrdered(L):
for i in range(len(L) - 1):
assert L[i] <= L[i+1], f'L = {L}, i = {i}'
In [ ]:
from collections import Counter
In [ ]:
def sameElements(L, S):
assert Counter(L) == Counter(S)
The function $\texttt{testSort}(n, k)$ generates $n$ random lists of length $k$, sorts them, and checks whether the output is sorted and contains the same elements as the input.
In [ ]:
def testSort(n, k):
for i in range(n):
L = [ rnd.randrange(2**31) for x in range(k) ]
oldL = L[:]
L = radixSort(L)
isOrdered(L)
sameElements(oldL, L)
print('.', end='')
print()
print("All tests successful!")
In [ ]:
%%time
testSort(100, 20000)
In [ ]:
k = 1000000
L = [ rnd.randrange(2*k) for x in range(k) ]
In [ ]:
%%time
S = radixSort(L)
In [ ]: