From 597f71a6b63f8f4cdb62647cf1668d930c853ed4 Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sat, 18 Jul 2020 04:34:25 +0900 Subject: [PATCH 01/10] Add merge insertion sort --- sorts/merge_insertion_sort.py | 103 ++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 sorts/merge_insertion_sort.py diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py new file mode 100644 index 000000000000..fa395fab60f4 --- /dev/null +++ b/sorts/merge_insertion_sort.py @@ -0,0 +1,103 @@ +""" +This is a pure Python implementation of the quick sort algorithm + +For doctests run following command: +python -m doctest -v merge_insertion_sort.py +or +python3 -m doctest -v merge_insertion_sort.py + +For manual testing run: +python merge_insertion_sort.py +""" + + +def mergeInsertionSort(collection): + """Pure implementation of merge-insertion sort algorithm in Python + + :param collection: some mutable ordered collection with heterogeneous + comparable items inside + :return: the same collection ordered by ascending + + Examples: + >>> mergeInsertionSort([0, 5, 3, 2, 2]) + [0, 2, 2, 3, 5] + + >>> mergeInsertionSort([]) + [] + + >>> mergeInsertionSort([-2, -5, -45]) + [-45, -5, -2] + """ + + def binary_search_insertion(sorted_list, item): + left = 0 + right = len(sorted_list) - 1 + while left <= right: + middle = (left + right) // 2 + if left == right: + if sorted_list[middle] < item: + left = middle + 1 + break + else: + break + elif sorted_list[middle] < item: + left = middle + 1 + else: + right = middle - 1 + sorted_list.insert(left, item) + return sorted_list + + def sortlist_2d(list_2d): + def merge(left, right): + result = [] + while left and right: + if left[0][0] < right[0][0]: + result.append(left.pop(0)) + else: + result.append(right.pop(0)) + return result + left + right + + length = len(list_2d) + if length <= 1: + return list_2d + middle = length // 2 + return merge(sortlist_2d(list_2d[:middle]), sortlist_2d(list_2d[middle:])) + + if len(collection) <= 1: + return collection + + two_paired_list = [] + is_surplus = False + for i in range(0, len(collection), 2): + if i == len(collection) - 1: + is_surplus = True + else: + if collection[i] < collection[i + 1]: + two_paired_list.append([collection[i], collection[i + 1]]) + else: + two_paired_list.append([collection[i + 1], collection[i]]) + sorted_list_2d = sortlist_2d(two_paired_list) + result = [i[0] for i in sorted_list_2d] + result.append(sorted_list_2d[-1][1]) + + if is_surplus: + pivot = collection[-1] + result = binary_search_insertion(result, pivot) + + is_surplus_inserted_before_this_index = False + for i in range(len(sorted_list_2d) - 1): + if result[i] == collection[-i]: + is_surplus_inserted_before_this_index = True + pivot = sorted_list_2d[i][1] + if is_surplus_inserted_before_this_index: + result = result[: i + 2] + binary_search_insertion(result[i + 2 :], pivot) + else: + result = result[: i + 1] + binary_search_insertion(result[i + 1 :], pivot) + + return result + + +if __name__ == "__main__": + user_input = input("Enter numbers separated by a comma:\n").strip() + unsorted = [int(item) for item in user_input.split(",")] + print(mergeInsertionSort(unsorted)) From 5b94776e7fc618a03625b893ab8f20a37b28d103 Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sat, 18 Jul 2020 04:36:31 +0900 Subject: [PATCH 02/10] Fix python naming conventions --- sorts/merge_insertion_sort.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index fa395fab60f4..48218a98d91c 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -11,7 +11,7 @@ """ -def mergeInsertionSort(collection): +def merge_insertion_sort(collection): """Pure implementation of merge-insertion sort algorithm in Python :param collection: some mutable ordered collection with heterogeneous @@ -19,13 +19,13 @@ def mergeInsertionSort(collection): :return: the same collection ordered by ascending Examples: - >>> mergeInsertionSort([0, 5, 3, 2, 2]) + >>> merge_insertion_sort([0, 5, 3, 2, 2]) [0, 2, 2, 3, 5] - >>> mergeInsertionSort([]) + >>> merge_insertion_sort([]) [] - >>> mergeInsertionSort([-2, -5, -45]) + >>> merge_insertion_sort([-2, -5, -45]) [-45, -5, -2] """ @@ -100,4 +100,4 @@ def merge(left, right): if __name__ == "__main__": user_input = input("Enter numbers separated by a comma:\n").strip() unsorted = [int(item) for item in user_input.split(",")] - print(mergeInsertionSort(unsorted)) + print(merge_insertion_sort(unsorted)) From 50c418511f446a2847acd0ec79cff7266908092d Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sat, 18 Jul 2020 19:17:36 +0900 Subject: [PATCH 03/10] Add wikipedia link --- sorts/merge_insertion_sort.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index 48218a98d91c..19ae3c2afb1b 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -1,5 +1,6 @@ """ -This is a pure Python implementation of the quick sort algorithm +This is a pure Python implementation of the merge-insertion sort algorithm +Source: https://en.wikipedia.org/wiki/Merge-insertion_sort For doctests run following command: python -m doctest -v merge_insertion_sort.py From 23adf9697df4f90a136a66c4698dd2ed909c818f Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sat, 18 Jul 2020 19:33:45 +0900 Subject: [PATCH 04/10] Add type hint --- sorts/merge_insertion_sort.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index 19ae3c2afb1b..ddd3d21a40c7 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -11,8 +11,10 @@ python merge_insertion_sort.py """ +from typing import List -def merge_insertion_sort(collection): + +def merge_insertion_sort(collection: List[int]) -> List[int]: """Pure implementation of merge-insertion sort algorithm in Python :param collection: some mutable ordered collection with heterogeneous @@ -23,8 +25,8 @@ def merge_insertion_sort(collection): >>> merge_insertion_sort([0, 5, 3, 2, 2]) [0, 2, 2, 3, 5] - >>> merge_insertion_sort([]) - [] + >>> merge_insertion_sort([99]) + [99] >>> merge_insertion_sort([-2, -5, -45]) [-45, -5, -2] From 880b0ac522305b826a3dcdf1c9bb8915c639a6fb Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sat, 18 Jul 2020 22:31:13 +0900 Subject: [PATCH 05/10] Fix python to python3 Co-authored-by: Christian Clauss --- sorts/merge_insertion_sort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index ddd3d21a40c7..91d739ee3a02 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -8,7 +8,7 @@ python3 -m doctest -v merge_insertion_sort.py For manual testing run: -python merge_insertion_sort.py +python3 merge_insertion_sort.py """ from typing import List From 219a4c893cde56dba5e747e94b23c920f4b25296 Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sat, 18 Jul 2020 22:32:37 +0900 Subject: [PATCH 06/10] Refactor doubled process in if-condition into one outside of if-condition Co-authored-by: Christian Clauss --- sorts/merge_insertion_sort.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index 91d739ee3a02..09e3419593ab 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -40,9 +40,7 @@ def binary_search_insertion(sorted_list, item): if left == right: if sorted_list[middle] < item: left = middle + 1 - break - else: - break + break elif sorted_list[middle] < item: left = middle + 1 else: From b7b66c3ef540f387bc4cd5ebbb87b1b140d3e3e8 Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sat, 18 Jul 2020 22:33:13 +0900 Subject: [PATCH 07/10] Refactor make python3 prior to python Co-authored-by: Christian Clauss --- sorts/merge_insertion_sort.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index 09e3419593ab..08ee11a57477 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -3,9 +3,9 @@ Source: https://en.wikipedia.org/wiki/Merge-insertion_sort For doctests run following command: -python -m doctest -v merge_insertion_sort.py -or python3 -m doctest -v merge_insertion_sort.py +or +python -m doctest -v merge_insertion_sort.py For manual testing run: python3 merge_insertion_sort.py From ad92692e781bb39becc291e7dc3896dc216ffd04 Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sun, 19 Jul 2020 03:27:17 +0900 Subject: [PATCH 08/10] Fix name of is_surplus into has_last_odd_item --- sorts/merge_insertion_sort.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index 08ee11a57477..a95635c4011e 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -68,10 +68,10 @@ def merge(left, right): return collection two_paired_list = [] - is_surplus = False + has_last_odd_item = False for i in range(0, len(collection), 2): if i == len(collection) - 1: - is_surplus = True + has_last_odd_item = True else: if collection[i] < collection[i + 1]: two_paired_list.append([collection[i], collection[i + 1]]) @@ -81,16 +81,16 @@ def merge(left, right): result = [i[0] for i in sorted_list_2d] result.append(sorted_list_2d[-1][1]) - if is_surplus: + if has_last_odd_item: pivot = collection[-1] result = binary_search_insertion(result, pivot) - is_surplus_inserted_before_this_index = False + is_last_odd_item_inserted_before_this_index = False for i in range(len(sorted_list_2d) - 1): if result[i] == collection[-i]: - is_surplus_inserted_before_this_index = True + is_last_odd_item_inserted_before_this_index = True pivot = sorted_list_2d[i][1] - if is_surplus_inserted_before_this_index: + if is_last_odd_item_inserted_before_this_index: result = result[: i + 2] + binary_search_insertion(result[i + 2 :], pivot) else: result = result[: i + 1] + binary_search_insertion(result[i + 1 :], pivot) From f0d1215c6c542a0f4458378f900679b496d93a5a Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sun, 19 Jul 2020 04:35:23 +0900 Subject: [PATCH 09/10] Add comment --- sorts/merge_insertion_sort.py | 73 +++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index a95635c4011e..3bc9dcb933c4 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -67,29 +67,102 @@ def merge(left, right): if len(collection) <= 1: return collection + """ + Group the items into two pairs, and leave one element if there is a last odd item. + + Example: [999, 100, 75, 40, 10000] + -> [999, 100], [75, 40]. Leave 10000. + """ two_paired_list = [] has_last_odd_item = False for i in range(0, len(collection), 2): if i == len(collection) - 1: has_last_odd_item = True else: + """ + Sort two-pairs in each groups. + + Example: [999, 100], [75, 40] + -> [100, 999], [40, 75] + """ if collection[i] < collection[i + 1]: two_paired_list.append([collection[i], collection[i + 1]]) else: two_paired_list.append([collection[i + 1], collection[i]]) + + """ + Sort two_paired_list. + + Example: [100, 999], [40, 75] + -> [40, 75], [100, 999] + """ sorted_list_2d = sortlist_2d(two_paired_list) + + """ + 40 < 100 is sure because it has already been sorted. + Generate the sorted_list of them so that you can avoid unnecessary comparison. + + Example: + group0 group1 + 40 100 + 75 999 + -> + group0 group1 + [40, 100] + 75 999 + """ result = [i[0] for i in sorted_list_2d] + + """ + 100 < 999 is sure because it has already been sorted. + Put 999 in last of the sorted_list so that you can avoid unnecessary comparison. + + Example: + group0 group1 + [40, 100] + 75 999 + -> + group0 group1 + [40, 100, 999] + 75 + """ result.append(sorted_list_2d[-1][1]) + """ + Insert the last odd item left if there is. + + Example: + group0 group1 + [40, 100, 999] + 75 + -> + group0 group1 + [40, 100, 999, 10000] + 75 + """ if has_last_odd_item: pivot = collection[-1] result = binary_search_insertion(result, pivot) + """ + Insert the remaining items. + In this case, 40 < 75 is sure because it has already been sorted. + Therefore, you only need to insert 75 into [100, 999, 10000] so that you can avoid unnecessary comparison. + + Example: + group0 group1 + [40, 100, 999, 10000] + ^ You don't need to compare with this as 40 < 75 is already sure. + 75 + -> + [40, 75, 100, 999, 10000] + """ is_last_odd_item_inserted_before_this_index = False for i in range(len(sorted_list_2d) - 1): if result[i] == collection[-i]: is_last_odd_item_inserted_before_this_index = True pivot = sorted_list_2d[i][1] + # If last_odd_item is inserted before the item's index, you should forward index one more. if is_last_odd_item_inserted_before_this_index: result = result[: i + 2] + binary_search_insertion(result[i + 2 :], pivot) else: From 8ed76fa2f1c633c68ccc1cf7601b99f2e7b18886 Mon Sep 17 00:00:00 2001 From: ryuta69 Date: Sun, 19 Jul 2020 04:43:06 +0900 Subject: [PATCH 10/10] Fix long comment to shorten --- sorts/merge_insertion_sort.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sorts/merge_insertion_sort.py b/sorts/merge_insertion_sort.py index 3bc9dcb933c4..339851699525 100644 --- a/sorts/merge_insertion_sort.py +++ b/sorts/merge_insertion_sort.py @@ -147,7 +147,8 @@ def merge(left, right): """ Insert the remaining items. In this case, 40 < 75 is sure because it has already been sorted. - Therefore, you only need to insert 75 into [100, 999, 10000] so that you can avoid unnecessary comparison. + Therefore, you only need to insert 75 into [100, 999, 10000], + so that you can avoid unnecessary comparison. Example: group0 group1 @@ -162,7 +163,8 @@ def merge(left, right): if result[i] == collection[-i]: is_last_odd_item_inserted_before_this_index = True pivot = sorted_list_2d[i][1] - # If last_odd_item is inserted before the item's index, you should forward index one more. + # If last_odd_item is inserted before the item's index, + # you should forward index one more. if is_last_odd_item_inserted_before_this_index: result = result[: i + 2] + binary_search_insertion(result[i + 2 :], pivot) else: