From d46a89664c3b6e43ed887cf37a2a4c78e2f371bf Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Wed, 11 Nov 2020 23:40:32 +0900 Subject: [PATCH 1/9] Create intro_sort.py --- sorts/intro_sort.py | 99 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 sorts/intro_sort.py diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py new file mode 100644 index 000000000000..420aeb763a7f --- /dev/null +++ b/sorts/intro_sort.py @@ -0,0 +1,99 @@ +""" +Introspective Sort is hybrid sort (Quick Sort + Heap Sort + Insertion Sort) +if the size of the list is under 16, use insertion sort + +""" +import math + + +def insertion_sort(array: list, start: int, end: int) -> list: + for i in range(start, end): + temp_index = i + temp_index_value = array[i] + while temp_index != start and temp_index_value < array[temp_index - 1]: + array[temp_index] = array[temp_index - 1] + temp_index -= 1 + array[temp_index] = temp_index_value + return array + + +def heapify(array: list, index: int, heap_size: int): # Max Heap + largest = index + left_index = 2 * index + 1 # Left Node + right_index = 2 * index + 2 # Right Node + + if left_index < heap_size and array[largest] < array[left_index]: + largest = left_index + + if right_index < heap_size and array[largest] < array[right_index]: + largest = right_index + + if largest != index: + array[index], array[largest] = array[largest], array[index] + heapify(array, largest, heap_size) + + +def heap_sort(array: list) -> list: + n = len(array) + + for i in range(n // 2, -1, -1): + heapify(array, n, i) + + for i in range(n - 1, 0, -1): + array[i], array[0] = array[0], array[i] + heapify(array, 0, i) + + return array + +def median_of_3(array: list, first_index: int, middle_index: int, last_index: int) -> int: + if (array[first_index] > array[middle_index]) != (array[first_index] > array[last_index]): + return array[first_index] + elif (array[middle_index] > array[first_index]) != (array[middle_index] > array[last_index]): + return array[middle_index] + else: + return array[last_index] + +def partition(array: list, low: int, high: int, pivot: int) -> int: + i = low + j = high + while True: + while array[i] < pivot: + i += 1 + j -= 1 + while pivot < array[j]: + j -= 1 + if i >= j: + return i + array[i], array[j] = array[j], array[i] + i += 1 + + +def sort(array: list): + max_depth = 2 * math.ceil(math.log2(len(array))) + size_threshold = 16 + return intro_sort(array, 0, len(array), size_threshold, max_depth) + + +def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth: int): + # if size > 16: heap sort or quick sort + while end - start > size_threshold: + if max_depth == 0: + return heap_sort(array) + max_depth -= 1 + pivot = median_of_3(array, start, start + ((end - start) // 2) + 1, end) + p = partition(array, start, end, pivot) + intro_sort(array, p, end, size_threshold, max_depth) + end = p + return insertion_sort(array) + + +if __name__ == "__main__": + user_input = input("Enter numbers separated by comma:\n") + unsorted = [int(x) for x in user_input.split(",")] + print(sort(unsorted)) + + + + + + From 164e0c87fd22052fc74992c17da0cbd01082b095 Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Thu, 12 Nov 2020 00:02:49 +0900 Subject: [PATCH 2/9] modified intro_sort.py --- sorts/intro_sort.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index 420aeb763a7f..7c904794d804 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -1,9 +1,9 @@ """ Introspective Sort is hybrid sort (Quick Sort + Heap Sort + Insertion Sort) if the size of the list is under 16, use insertion sort - """ import math +import random def insertion_sort(array: list, start: int, end: int) -> list: @@ -45,14 +45,22 @@ def heap_sort(array: list) -> list: return array -def median_of_3(array: list, first_index: int, middle_index: int, last_index: int) -> int: - if (array[first_index] > array[middle_index]) != (array[first_index] > array[last_index]): + +def median_of_3( + array: list, first_index: int, middle_index: int, last_index: int +) -> int: + if (array[first_index] > array[middle_index]) != ( + array[first_index] > array[last_index] + ): return array[first_index] - elif (array[middle_index] > array[first_index]) != (array[middle_index] > array[last_index]): + elif (array[middle_index] > array[first_index]) != ( + array[middle_index] > array[last_index] + ): return array[middle_index] else: return array[last_index] + def partition(array: list, low: int, high: int, pivot: int) -> int: i = low j = high @@ -88,12 +96,8 @@ def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth if __name__ == "__main__": - user_input = input("Enter numbers separated by comma:\n") - unsorted = [int(x) for x in user_input.split(",")] - print(sort(unsorted)) - - - - - + array = [] + for i in range(30): + array.append(random.randrange(100)) + assert sort(array) == sorted(array) From 2d55dcda26696f5e34631439c3c1833f4395ead0 Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Fri, 13 Nov 2020 18:00:29 +0900 Subject: [PATCH 3/9] add doctest --- sorts/intro_sort.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index 7c904794d804..c1acf3761c81 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -1,9 +1,9 @@ """ Introspective Sort is hybrid sort (Quick Sort + Heap Sort + Insertion Sort) if the size of the list is under 16, use insertion sort +https://en.wikipedia.org/wiki/Introsort """ import math -import random def insertion_sort(array: list, start: int, end: int) -> list: @@ -17,7 +17,7 @@ def insertion_sort(array: list, start: int, end: int) -> list: return array -def heapify(array: list, index: int, heap_size: int): # Max Heap +def heapify(array: list, index: int, heap_size: int) -> None: # Max Heap largest = index left_index = 2 * index + 1 # Left Node right_index = 2 * index + 2 # Right Node @@ -46,9 +46,7 @@ def heap_sort(array: list) -> list: return array -def median_of_3( - array: list, first_index: int, middle_index: int, last_index: int -) -> int: +def median_of_3(array: list, first_index: int, middle_index: int, last_index: int) -> int: if (array[first_index] > array[middle_index]) != ( array[first_index] > array[last_index] ): @@ -83,7 +81,18 @@ def sort(array: list): def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth: int): - # if size > 16: heap sort or quick sort + """ + :param collection: some mutable ordered collection with heterogeneous + comparable items inside + :return: the same collection ordered by ascending + + Examples: + >>> sort([4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]) + [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] + + >>> sort([-1, -5, -3, -13, -44]) + [-44, -13, -5, -3, -1] + """ while end - start > size_threshold: if max_depth == 0: return heap_sort(array) @@ -92,12 +101,14 @@ def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth p = partition(array, start, end, pivot) intro_sort(array, p, end, size_threshold, max_depth) end = p - return insertion_sort(array) + return insertion_sort(array, start, end) if __name__ == "__main__": - array = [] - for i in range(30): - array.append(random.randrange(100)) + import doctest - assert sort(array) == sorted(array) + doctest.testmod() + + user_input = input("Enter numbers separated by a comma:\n").strip() + unsorted = [int(item) for item in user_input.split(",")] + print(sort(unsorted)) From 40c9a3221f13282e8143b5921746284ed6059476 Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Fri, 13 Nov 2020 18:03:39 +0900 Subject: [PATCH 4/9] modified code black intro_sort.py --- sorts/intro_sort.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index c1acf3761c81..3d1b607da355 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -46,7 +46,9 @@ def heap_sort(array: list) -> list: return array -def median_of_3(array: list, first_index: int, middle_index: int, last_index: int) -> int: +def median_of_3( + array: list, first_index: int, middle_index: int, last_index: int +) -> int: if (array[first_index] > array[middle_index]) != ( array[first_index] > array[last_index] ): From d266cfe1f48322531793da643170242f255b0ecb Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Sun, 15 Nov 2020 20:21:57 +0900 Subject: [PATCH 5/9] add more test --- sorts/intro_sort.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index 3d1b607da355..c9bbfea07979 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -77,6 +77,8 @@ def partition(array: list, low: int, high: int, pivot: int) -> int: def sort(array: list): + if len(array) == 0: + return array max_depth = 2 * math.ceil(math.log2(len(array))) size_threshold = 16 return intro_sort(array, 0, len(array), size_threshold, max_depth) @@ -94,6 +96,21 @@ def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth >>> sort([-1, -5, -3, -13, -44]) [-44, -13, -5, -3, -1] + + >>> sort([]) + [] + + >>> sort([5]) + [5] + + >>> sort([-3, 0, -7, 6, 23, -34]) + [-34, -7, -3, 0, 6, 23] + + >>> sort([1.7, 1.0, 3.3, 2.1, 0.3 ]) + [0.3, 1.0, 1.7, 2.1, 3.3] + + >>> sort(['d', 'a', 'b', 'e', 'c']) + ['a', 'b', 'c', 'd', 'e'] """ while end - start > size_threshold: if max_depth == 0: @@ -111,6 +128,6 @@ def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth doctest.testmod() - user_input = input("Enter numbers separated by a comma:\n").strip() + user_input = input("Enter numbers separated by a comma : ").strip() unsorted = [int(item) for item in user_input.split(",")] print(sort(unsorted)) From 27582db579a5afb8176aeeca374e26a2a12dae89 Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Mon, 23 Nov 2020 21:17:19 +0900 Subject: [PATCH 6/9] Update intro_sort.py added doctest, modified code --- sorts/intro_sort.py | 89 ++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index c9bbfea07979..3fda1bb7a9b8 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -7,6 +7,12 @@ def insertion_sort(array: list, start: int, end: int) -> list: + """ + >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] + + >>> insertion_sort(array, 0, len(array)) + [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] + """ for i in range(start, end): temp_index = i temp_index_value = array[i] @@ -18,6 +24,11 @@ def insertion_sort(array: list, start: int, end: int) -> list: def heapify(array: list, index: int, heap_size: int) -> None: # Max Heap + """ + >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] + + >>> heapify(array, len(array) // 2 ,len(array)) + """ largest = index left_index = 2 * index + 1 # Left Node right_index = 2 * index + 2 # Right Node @@ -34,10 +45,16 @@ def heapify(array: list, index: int, heap_size: int) -> None: # Max Heap def heap_sort(array: list) -> list: + """ + >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] + + >>> heap_sort(array) + [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] + """ n = len(array) for i in range(n // 2, -1, -1): - heapify(array, n, i) + heapify(array, i, n) for i in range(n - 1, 0, -1): array[i], array[0] = array[0], array[i] @@ -49,6 +66,12 @@ def heap_sort(array: list) -> list: def median_of_3( array: list, first_index: int, middle_index: int, last_index: int ) -> int: + """ + >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] + + >>> median_of_3(array, 0, 0 + ((len(array) - 0) // 2) + 1, len(array) - 1) + 12 + """ if (array[first_index] > array[middle_index]) != ( array[first_index] > array[last_index] ): @@ -62,6 +85,12 @@ def median_of_3( def partition(array: list, low: int, high: int, pivot: int) -> int: + """ + >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] + + >>> partition(array, 0, len(array), 12) + 8 + """ i = low j = high while True: @@ -77,6 +106,33 @@ def partition(array: list, low: int, high: int, pivot: int) -> int: def sort(array: list): + """ + :param collection: some mutable ordered collection with heterogeneous + comparable items inside + :return: the same collection ordered by ascending + + Examples: + >>> sort([4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]) + [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] + + >>> sort([-1, -5, -3, -13, -44]) + [-44, -13, -5, -3, -1] + + >>> sort([]) + [] + + >>> sort([5]) + [5] + + >>> sort([-3, 0, -7, 6, 23, -34]) + [-34, -7, -3, 0, 6, 23] + + >>> sort([1.7, 1.0, 3.3, 2.1, 0.3 ]) + [0.3, 1.0, 1.7, 2.1, 3.3] + + >>> sort(['d', 'a', 'b', 'e', 'c']) + ['a', 'b', 'c', 'd', 'e'] + """ if len(array) == 0: return array max_depth = 2 * math.ceil(math.log2(len(array))) @@ -86,37 +142,18 @@ def sort(array: list): def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth: int): """ - :param collection: some mutable ordered collection with heterogeneous - comparable items inside - :return: the same collection ordered by ascending - - Examples: - >>> sort([4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]) - [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] - - >>> sort([-1, -5, -3, -13, -44]) - [-44, -13, -5, -3, -1] + >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] - >>> sort([]) - [] + >>> max_depth = 2 * math.ceil(math.log2(len(array))) - >>> sort([5]) - [5] - - >>> sort([-3, 0, -7, 6, 23, -34]) - [-34, -7, -3, 0, 6, 23] - - >>> sort([1.7, 1.0, 3.3, 2.1, 0.3 ]) - [0.3, 1.0, 1.7, 2.1, 3.3] - - >>> sort(['d', 'a', 'b', 'e', 'c']) - ['a', 'b', 'c', 'd', 'e'] + >>> intro_sort(array, 0, len(array), 16, max_depth) + [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] """ while end - start > size_threshold: if max_depth == 0: return heap_sort(array) max_depth -= 1 - pivot = median_of_3(array, start, start + ((end - start) // 2) + 1, end) + pivot = median_of_3(array, start, start + ((end - start) // 2) + 1, end - 1) p = partition(array, start, end, pivot) intro_sort(array, p, end, size_threshold, max_depth) end = p @@ -129,5 +166,5 @@ def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth doctest.testmod() user_input = input("Enter numbers separated by a comma : ").strip() - unsorted = [int(item) for item in user_input.split(",")] + unsorted = [float(item) for item in user_input.split(",")] print(sort(unsorted)) From 3be2c7578a5a6f4aeb0b0ed70334e337f7251cb4 Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Mon, 23 Nov 2020 21:20:45 +0900 Subject: [PATCH 7/9] black intro_sort.py --- sorts/intro_sort.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index 3fda1bb7a9b8..1730b069809e 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -107,32 +107,32 @@ def partition(array: list, low: int, high: int, pivot: int) -> int: def sort(array: list): """ - :param collection: some mutable ordered collection with heterogeneous - comparable items inside - :return: the same collection ordered by ascending + :param collection: some mutable ordered collection with heterogeneous + comparable items inside + :return: the same collection ordered by ascending - Examples: - >>> sort([4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]) - [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] + Examples: + >>> sort([4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12]) + [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] - >>> sort([-1, -5, -3, -13, -44]) - [-44, -13, -5, -3, -1] + >>> sort([-1, -5, -3, -13, -44]) + [-44, -13, -5, -3, -1] - >>> sort([]) - [] + >>> sort([]) + [] - >>> sort([5]) - [5] + >>> sort([5]) + [5] - >>> sort([-3, 0, -7, 6, 23, -34]) - [-34, -7, -3, 0, 6, 23] + >>> sort([-3, 0, -7, 6, 23, -34]) + [-34, -7, -3, 0, 6, 23] - >>> sort([1.7, 1.0, 3.3, 2.1, 0.3 ]) - [0.3, 1.0, 1.7, 2.1, 3.3] + >>> sort([1.7, 1.0, 3.3, 2.1, 0.3 ]) + [0.3, 1.0, 1.7, 2.1, 3.3] - >>> sort(['d', 'a', 'b', 'e', 'c']) - ['a', 'b', 'c', 'd', 'e'] - """ + >>> sort(['d', 'a', 'b', 'e', 'c']) + ['a', 'b', 'c', 'd', 'e'] + """ if len(array) == 0: return array max_depth = 2 * math.ceil(math.log2(len(array))) From 76dae8cadbfd1887e8ce7f62f3ce68243265f264 Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Tue, 24 Nov 2020 15:02:38 +0900 Subject: [PATCH 8/9] add type hint --- sorts/intro_sort.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index 1730b069809e..60aaff695c17 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -105,7 +105,7 @@ def partition(array: list, low: int, high: int, pivot: int) -> int: i += 1 -def sort(array: list): +def sort(array: list) -> list: """ :param collection: some mutable ordered collection with heterogeneous comparable items inside @@ -140,7 +140,9 @@ def sort(array: list): return intro_sort(array, 0, len(array), size_threshold, max_depth) -def intro_sort(array: list, start: int, end: int, size_threshold: int, max_depth: int): +def intro_sort( + array: list, start: int, end: int, size_threshold: int, max_depth: int +) -> list: """ >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] From d0e632b069daf573cb2eba034d8cdd1a7be180de Mon Sep 17 00:00:00 2001 From: yeonjeonglee Date: Wed, 25 Nov 2020 15:36:24 +0900 Subject: [PATCH 9/9] modified code --- sorts/intro_sort.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sorts/intro_sort.py b/sorts/intro_sort.py index 60aaff695c17..f0e3645adbb7 100644 --- a/sorts/intro_sort.py +++ b/sorts/intro_sort.py @@ -6,13 +6,14 @@ import math -def insertion_sort(array: list, start: int, end: int) -> list: +def insertion_sort(array: list, start: int = 0, end: int = 0) -> list: """ >>> array = [4, 2, 6, 8, 1, 7, 8, 22, 14, 56, 27, 79, 23, 45, 14, 12] >>> insertion_sort(array, 0, len(array)) [1, 2, 4, 6, 7, 8, 8, 12, 14, 14, 22, 23, 27, 45, 56, 79] """ + end = end or len(array) for i in range(start, end): temp_index = i temp_index_value = array[i]