# author Ttssxuan
# chapter 8.1
# the counting sort
def counting_sort(arr, brr, k):
'''
use the counting sort algorithm to sorting arr place it in brr
Parameters:
arr - the array need to be sorted
brr - the result sorted
k - the max numbe of arr
Returns:
none
'''
c = [0] * (k + 1)
# count the number of the element in arr equals i
for j in range(0, len(arr)):
c[arr[j]] = c[arr[j]] + 1
# count the number of the element in arr less than or equals i
for i in range(1, k + 1):
c[i] = c[i] + c[i - 1]
# find the appropriate place for arr[j]
for j in range(len(arr) - 1, -1, -1):
brr[c[arr[j]] - 1] = arr[j]
# counting the next place for arr[j] if it exist again
c[arr[j]] = c[arr[j]] - 1
# test
arr = [1, 2, 4, 9, 0, 10, 2, 4, 9, 6, 8]
brr = [0] * len(arr)
counting_sort(arr, brr, 10)
print(brr)
# 8.2-4
def preprocessing(arr, k):
'''
use the counting sort algorithm to count the number of the element in arr
less than or equals to i
Parameters:
arr - the array need to be sorted
k - the max numbe of arr
Returns:
the counting info
'''
c = [0] * (k + 1)
# count the number of the element in arr equals i
for j in range(0, len(arr)):
c[arr[j]] = c[arr[j]] + 1
# count the number of the element in arr less than or equals i
print(c)
for i in range(1, k + 1):
c[i] = c[i] + c[i - 1]
return c
def query(a, b, c):
'''
get the number of elements between a, b
Parameters:
a - the beginning of the scope
b - the ending of the scope
c - the counting info array
Returns:
the number of elements between a, b
'''
if a != 0:
return c[b] - c[a - 1]
else:
return c[b]
# test
arr = [1, 2, 4, 9, 0, 10, 2, 4, 9, 6, 8]
c = preprocessing(arr, 10)
print(c)
print('1, 4', query(1, 4, c))
print('2, 9', query(2, 9, c))
print('3, 5', query(3, 5, c))
# author Ttssxuan
# chapter 8.1
# the radix sort
def counting_sort(arr, k, position):
'''
sort arr use count sort, at position whit k digite
Parameters:
arr - the array need to be sort
k - the number of element
position - the present position need to be sort
'''
c = [0] * k
brr = [0] * len(arr)
temp_arr = [0] * len(arr)
# get the position i number
for i in range(0, len(arr)):
temp_arr[i] = (arr[i] // 10 ** (position - 1)) % 10
# get the count number
for j in range(0, len(temp_arr)):
c[temp_arr[j]] += 1
for i in range(1, k):
c[i] += c[i - 1]
# sort arr
for j in range(len(temp_arr) - 1, -1, -1):
brr[c[temp_arr[j]] - 1] = arr[j]
c[temp_arr[j]] = c[temp_arr[j]] - 1
return brr
def radix_sort(arr, k, d):
'''
use radix sort algorithm sorting the arr
Parameters:
arr - the array need to be sort
k - the possiblity of value
d - the length of each digit
'''
# use counting sort algorithm sort every position
for i in range(1, d + 1):
arr = counting_sort(arr, k, i)
return arr
# test
arr = [5556, 2023, 1239, 9875, 2491, 9931, 5955, 1035, 4025]
arr = radix_sort(arr, 10, 4)
print(arr)
# author Ttssxuan
# 8.3-1
# use the radix sort algorithm to sort some words
def counting_sort(arr, k, position):
'''
use counting sort algorithm sort the array, by its index position element
Parameters:
arr - the array need to be sort
k - the vary number of the element
position - the index of the array
Returns:
a sorted array by the index position of the array
'''
c = [0] * k
brr = [0] * len(arr)
# count the number of the arr[j][position] equals j
for j in range(0, len(arr)):
c[ord(arr[j][position]) - ord('A')] += 1
# count the number of the arr[j][position] less than or equals j
for i in range(1, k):
c[i] += c[i - 1]
# find the position for arr[j]
for j in range(len(arr) - 1, -1, -1):
brr[c[ord(arr[j][position]) - ord('A')] - 1] = arr[j]
c[ord(arr[j][position]) - ord('A')] -= 1
return brr
def radix_sort(arr, k, d):
'''
sort the arr, and the arr's element is string
Parameters:
arr - the array need to be sorted
k - the vary value of the element
d - the len of the element
'''
for i in range(d - 1, -1, -1):
arr = counting_sort(arr, k, i)
return arr
# test
arr = ['COW', 'DOG', 'SEA', 'RUG', 'ROW', 'MOB', 'BOX', 'TAB', 'BAR', 'EAR',
'TAR', 'DIG', 'BIG', 'TEA', 'NOW', 'FOX']
arr = radix_sort(arr, 26, 3)
print(arr)
# author Ttssxuan
# chapter 8.4
# the bucket sort
from math import floor
def insert_sort(arr):
'''
use insert sort algorithm to sort the arr
Parameters:
arr - the array need to be sorted
Returns:
none
'''
for i in range(1, len(arr)):
x = arr[i]
j = i - 1
while j >= 0 and x < arr[j]:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = x
def bucket_sort(arr):
'''
use the backet sort algorithm to sort the arr
Parameters:
arr - the array need to be sorted
Returns:
the sorted arr
'''
# get the length
n = len(arr)
# make the backet
brr = [[] for i in range(0, n)]
# distribute the elements in arr to the backets
for i in range(0, n):
brr[int(floor(n * arr[i]))].append(arr[i])
# sort the elements in each backet
for i in range(0, n):
insert_sort(brr[i])
# concatenate the array
if i != 0:
brr[0] += brr[i]
return brr[0]
# test
arr = [0.1, 0.01, 0.5, 0.4, 0.22, 0.98, 0.34, 0.33]
brr = bucket_sort(arr)
print(brr)
# author Ttssxuan
# 8-3
# sorting variable-lenth items
# 8-3 a
def counting_sort(arr, k, position):
'''
sort arr use count sort, at position whit k digite
Parameters:
arr - the array need to be sort
k - the number of element
position - the present position need to be sort
'''
c = [0] * k
brr = [0] * len(arr)
temp_arr = [0] * len(arr)
# get the position i number
for i in range(0, len(arr)):
temp_arr[i] = (arr[i] // 10 ** (position - 1)) % 10
# get the count number
for j in range(0, len(temp_arr)):
c[temp_arr[j]] += 1
for i in range(1, k):
c[i] += c[i - 1]
# sort arr
for j in range(len(temp_arr) - 1, -1, -1):
brr[c[temp_arr[j]] - 1] = arr[j]
c[temp_arr[j]] = c[temp_arr[j]] - 1
return brr
def radix_sort(arr, k, d):
'''
use radix sort algorithm sorting the arr
Parameters:
arr - the array need to be sort
k - the possiblity of value
d - the length of each digit
'''
# use counting sort algorithm sort every position
if len(arr) == 0:
return []
for i in range(1, d + 1):
arr = counting_sort(arr, k, i)
return arr
def sort_n_width_number(arr, n):
'''
sort an array of number whose total digits number equals n, in O(n)
Parameters:
arr - the array need to be sort
n - the total number of digits
'''
# use the counting sort divide the arr into groups and the elements in
# each group has the same number of digits
c = [0] * (n + 1)
place = [0] * (n + 1)
brr = [0] * len(arr)
for i in range(0, len(arr)):
c[len(str(arr[i]))] += 1
for i in range(1, n + 1):
c[i] += c[i - 1]
for i in range(0, n + 1):
place[i] = c[i]
# divide into groups
for j in range(len(arr) - 1, -1, -1):
brr[c[len(str(arr[j]))] - 1] = arr[j]
c[len(str(arr[j]))] -= 1
# use radix sort algorithm sorting each group
for i in range(1, n + 1):
brr[place[i - 1]:place[i]] = radix_sort(brr[place[i - 1]:place[i]], 10, i)
return brr
# test sort_n_width_number
arr = [1, 3, 22, 44, 34, 42, 6, 334, 223, 555]
brr = sort_n_width_number(arr, 20)
print(brr)
arr = [13, 5, 333, 22, 2, 59, 0, 44, 34, 42, 6, 334, 223, 555]
brr = sort_n_width_number(arr, 28)
print(brr)
# 8-3 b
def sort_n_width_string(arr, n):
'''
sort the arr with total n characters by a lexicographically with O(n) time
Parameters:
arr - the array needs to be sorted
n - the total number of characters in the array
Returns:
the sorted arr
'''
c = [0] * 53
place = [0] * 53
brr = [0] * len(arr)
# there is no need to calculating
if len(arr) == 0:
return arr
# count the number of strings which beginning with conrespond letter
for i in range(0, len(arr)):
if len(arr[i]) <= n:
c[0] += 1
elif ord(arr[i][n]) >= 97:
c[27 + ord(arr[i][n]) - 97] += 1
else:
c[1 + ord(arr[i][n]) - 65] += 1
# there are only empty strings, no need to calculating
if c[0] == len(arr):
return arr
# counting the number of strings less than current string
for i in range(1, 53):
c[i] += c[i - 1]
place[i] = c[i]
# find the appropriate place for the string
for i in range(len(arr) - 1, -1, -1):
if len(arr[i]) <= n:
brr[c[0] - 1] = arr[i]
c[0] -= 1
elif ord(arr[i][n]) >= 97:
brr[c[27 + ord(arr[i][n]) - 97] - 1] = arr[i]
c[27 + ord(arr[i][n]) - 97] -= 1
else:
brr[c[1 + ord(arr[i][n]) - 65] - 1] = arr[i]
c[1 + ord(arr[i][n]) - 65] -= 1
# recurrence sort the subarray
for i in range(1, 53):
brr[place[i - 1]:place[i]] = sort_n_width_string(brr[place[i - 1]:place[i]], n + 1)
return brr
# test sort_n_width_string
arr = ['aa', 'b', '', 'c', 'addb', 'calkd', 'bd', 'ab', 'abcd', 'sssa']
brr = sort_n_width_string(arr, 0)
print(brr)
arr = ['aa', 'b', 'C', 'A', 'B', 'CDE', 'DDSE', '', 'c', 'addb', 'calkd', 'bd', 'ab', 'abcd', 'sssa']
brr = sort_n_width_string(arr, 0)
print(brr)
# author Ttssxuan
# 8-4
# the water jugs problem
import random
# define the jug class
class jug:
def __init__(self, pos, volume):
self.pos = pos
self.volume = volume
def split(arr, key, p, r):
'''
split the arr[p..r] into two part, arr[p..i] < key, arr[i + 1..r] >= key
Parameters:
arr - the arr need to be splited
key - the pivot
p - the start index of the arr
r - the end index of the arr
Returns:
the split point
'''
i = p - 1
# split the array
for j in range(p, r + 1):
if arr[j].volume < key:
i += 1
arr[i], arr[j] = arr[j], arr[i]
return i
def match_jugs(rrr, rs, re, brr, bs, be):
'''
solve the match jugs problem as the quicksort, and output the pair
Parameters:
rrr - the red jugs
rs - the beginning of the red jugs
re - the ending of the blue jugs
brr - the blue jugs
bs - the beginning of the blue jugs
be - the ending of the blue jugs
Returns:
none
'''
if rs > re:
return
if rs == re:
print("pair red:", rrr[rs].pos, "blue:", brr[bs].pos)
return
else:
ra = random.randint(rs, re)
rrr[ra], rrr[re] = rrr[re], rrr[ra]
split_r = split(rrr, rrr[re].volume, rs, re)
split_b = split(brr, rrr[re].volume, bs, be)
match_jugs(rrr, rs, split_r, brr, bs, split_b)
match_jugs(rrr, split_r + 1, re, brr, split_b + 1, be)
# test match_jugs
print("test 1")
rrr = [jug(0, 4), jug(1, 2), jug(2, 6), jug(3, 11), jug(4, 23), jug(5, 10)]
brr = [jug(0, 6), jug(1, 2), jug(2, 4), jug(3, 23), jug(4, 10), jug(5, 11)]
match_jugs(rrr, 0, len(rrr) - 1, brr, 0, len(brr) - 1)
print("test 2")
rrr = [jug(0, 4)]
brr = [jug(0, 4)]
match_jugs(rrr, 0, len(rrr) - 1, brr, 0, len(brr) - 1)