diff --git a/sorts/msd_radix_sort.py b/sorts/msd_radix_sort.py index ee152bbc6..4c3cea30e 100644 --- a/sorts/msd_radix_sort.py +++ b/sorts/msd_radix_sort.py @@ -74,6 +74,86 @@ def _msd_radix_sort(list_of_ints: List[int], bit_position: int) -> List[int]: return res +def msd_radix_sort_inplace(list_of_ints: List[int]): + """ + Inplace implementation of the MSD radix sort algorithm. + Sorts based on the binary representation of the integers. + >>> lst = [1, 345, 23, 89, 0, 3] + >>> msd_radix_sort_inplace(lst) + >>> lst == sorted(lst) + True + >>> lst = [1, 43, 0, 0, 0, 24, 3, 3] + >>> msd_radix_sort_inplace(lst) + >>> lst == sorted(lst) + True + >>> lst = [] + >>> msd_radix_sort_inplace(lst) + >>> lst == [] + True + >>> lst = [-1, 34, 23, 4, -42] + >>> msd_radix_sort_inplace(lst) + Traceback (most recent call last): + ... + ValueError: All numbers must be positive + """ + + length = len(list_of_ints) + if not list_of_ints or length == 1: + return + + if min(list_of_ints) < 0: + raise ValueError("All numbers must be positive") + + most_bits = max(len(bin(x)[2:]) for x in list_of_ints) + _msd_radix_sort_inplace(list_of_ints, most_bits, 0, length) + + +def _msd_radix_sort_inplace( + list_of_ints: List[int], bit_position: int, begin_index: int, end_index: int +): + """ + Sort the given list based on the bit at bit_position. Numbers with a + 0 at that position will be at the start of the list, numbers with a + 1 at the end. + >>> lst = [45, 2, 32, 24, 534, 2932] + >>> _msd_radix_sort_inplace(lst, 1, 0, 3) + >>> lst == [32, 2, 45, 24, 534, 2932] + True + >>> lst = [0, 2, 1, 3, 12, 10, 4, 90, 54, 2323, 756] + >>> _msd_radix_sort_inplace(lst, 2, 4, 7) + >>> lst == [0, 2, 1, 3, 12, 4, 10, 90, 54, 2323, 756] + True + """ + if bit_position == 0 or end_index - begin_index <= 1: + return + + bit_position -= 1 + + i = begin_index + j = end_index - 1 + while i <= j: + changed = False + if not ((list_of_ints[i] >> bit_position) & 1): + # found zero at the beginning + i += 1 + changed = True + if (list_of_ints[j] >> bit_position) & 1: + # found one at the end + j -= 1 + changed = True + + if changed: + continue + + list_of_ints[i], list_of_ints[j] = list_of_ints[j], list_of_ints[i] + j -= 1 + if not j == i: + i += 1 + + _msd_radix_sort_inplace(list_of_ints, bit_position, begin_index, i) + _msd_radix_sort_inplace(list_of_ints, bit_position, i, end_index) + + if __name__ == "__main__": import doctest