diff --git a/sorts/dutch_national_flag_sort.py b/sorts/dutch_national_flag_sort.py new file mode 100644 index 000000000..79afefa73 --- /dev/null +++ b/sorts/dutch_national_flag_sort.py @@ -0,0 +1,100 @@ +""" +A pure implementation of Dutch national flag (DNF) sort algorithm in Python. +Dutch National Flag algorithm is an algorithm originally designed by Edsger Dijkstra. +It is the most optimal sort for 3 unique values (eg. 0, 1, 2) in a sequence. DNF can +sort a sequence of n size with [0 <= a[i] <= 2] at guaranteed O(n) complexity in a +single pass. + +The flag of the Netherlands consists of three colors: white, red, and blue. +The task is to randomly arrange balls of white, red, and blue in such a way that balls +of the same color are placed together. DNF sorts a sequence of 0, 1, and 2's in linear +time that does not consume any extra space. This algorithm can be implemented only on +a sequence that contains three unique elements. + +1) Time complexity is O(n). +2) Space complexity is O(1). + +More info on: https://en.wikipedia.org/wiki/Dutch_national_flag_problem + +For doctests run following command: +python3 -m doctest -v dutch_national_flag_sort.py + +For manual testing run: +python dnf_sort.py +""" + + +# Python program to sort a sequence containing only 0, 1 and 2 in a single pass. +red = 0 # The first color of the flag. +white = 1 # The second color of the flag. +blue = 2 # The third color of the flag. +colors = (red, white, blue) + + +def dutch_national_flag_sort(sequence: list) -> list: + """ + A pure Python implementation of Dutch National Flag sort algorithm. + :param data: 3 unique integer values (e.g., 0, 1, 2) in an sequence + :return: The same collection in ascending order + + >>> dutch_national_flag_sort([]) + [] + >>> dutch_national_flag_sort([0]) + [0] + >>> dutch_national_flag_sort([2, 1, 0, 0, 1, 2]) + [0, 0, 1, 1, 2, 2] + >>> dutch_national_flag_sort([0, 1, 1, 0, 1, 2, 1, 2, 0, 0, 0, 1]) + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2] + >>> dutch_national_flag_sort("abacab") + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort("Abacab") + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort([3, 2, 3, 1, 3, 0, 3]) + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort([-1, 2, -1, 1, -1, 0, -1]) + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + >>> dutch_national_flag_sort([1.1, 2, 1.1, 1, 1.1, 0, 1.1]) + Traceback (most recent call last): + ... + ValueError: The elements inside the sequence must contains only (0, 1, 2) values + """ + if not sequence: + return [] + if len(sequence) == 1: + return list(sequence) + low = 0 + high = len(sequence) - 1 + mid = 0 + while mid <= high: + if sequence[mid] == colors[0]: + sequence[low], sequence[mid] = sequence[mid], sequence[low] + low += 1 + mid += 1 + elif sequence[mid] == colors[1]: + mid += 1 + elif sequence[mid] == colors[2]: + sequence[mid], sequence[high] = sequence[high], sequence[mid] + high -= 1 + else: + raise ValueError( + f"The elements inside the sequence must contains only {colors} values" + ) + return sequence + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + user_input = input("Enter numbers separated by commas:\n").strip() + unsorted = [int(item.strip()) for item in user_input.split(",")] + print(f"{dutch_national_flag_sort(unsorted)}")