From 577bee0d88798b7b1bc00f5d00a43a5a0ff84df7 Mon Sep 17 00:00:00 2001 From: Nikolay Borysov Date: Wed, 23 Oct 2019 01:11:31 +0300 Subject: [PATCH] Add tim-sort sorting algorithm realization --- array/sort/tim-sort/Readme.md | 16 ++++++ array/sort/tim-sort/tim_sort.go | 73 ++++++++++++++++++++++++++++ array/sort/tim-sort/tim_sort_test.go | 37 ++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 array/sort/tim-sort/Readme.md create mode 100644 array/sort/tim-sort/tim_sort.go create mode 100644 array/sort/tim-sort/tim_sort_test.go diff --git a/array/sort/tim-sort/Readme.md b/array/sort/tim-sort/Readme.md new file mode 100644 index 0000000..8e885cc --- /dev/null +++ b/array/sort/tim-sort/Readme.md @@ -0,0 +1,16 @@ +# Tim-sort +Tim-sort is a sorting algorithm derived from insertion sort and merge sort. It was designed to perform in an optimal way on different kind of real world data. It is an adaptive sorting algorithm which needs O(n log n) comparisons to sort an array of n elements. It was designed and implemented by Tim Peters in 2002 in python programming language. It has been python's standard sorting algorithm since version 2.3. + +### Algorithm +1. Divide the array into the number of blocks known as run. +2. Consider size of run either 32 or 64(in the below implementation, size of run is 32.) +3. Sort the individual elements of every run one by one using insertion sort. +4. Merge the sorted runs one by one using merge function of merge sort. +5. Double the size of merged sub-arrays after every iteration. + +### Complexity +``` +Worst Case Time Complexity: O(n log n) +Best Case Time Complexity: O(n) +Average Time Complexity: O(n log n) +``` diff --git a/array/sort/tim-sort/tim_sort.go b/array/sort/tim-sort/tim_sort.go new file mode 100644 index 0000000..353e7ce --- /dev/null +++ b/array/sort/tim-sort/tim_sort.go @@ -0,0 +1,73 @@ +package sort + +const run int = 32 + +func TimSort(a []int) { + for i := 0; i < len(a); i += run { + insertionSort(a, i, minimum(i+31, len(a)-1)) + } + for size := run; size < len(a); size = 2 * size { + for begin := 0; begin < len(a); begin += 2 * size { + middle := begin + size - 1 + end := minimum((begin + 2*size - 1), (len(a) - 1)) + if end < middle { + continue + } + merge(a, begin, middle, end) + } + } +} + +func insertionSort(a []int, begin, end int) { + for i := begin + 1; i <= end; i++ { + temp := a[i] + j := i - 1 + for j >= begin && a[j] > temp { + a[j+1] = a[j] + j-- + } + a[j+1] = temp + } +} + +func merge(a []int, left, middle, right int) { + len1 := middle - left + 1 + len2 := right - middle + begin := make([]int, len1) + end := make([]int, len2) + for i := 0; i < len1; i++ { + begin[i] = a[left+i] + } + for i := 0; i < len2; i++ { + end[i] = a[middle+1+i] + } + var i, j int + k := left + for i < len1 && j < len2 { + if begin[i] <= end[j] { + a[k] = begin[i] + i++ + } else { + a[k] = end[j] + j++ + } + k++ + } + for i < len1 { + a[k] = begin[i] + k++ + i++ + } + for j < len2 { + a[k] = end[j] + k++ + j++ + } +} + +func minimum(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/array/sort/tim-sort/tim_sort_test.go b/array/sort/tim-sort/tim_sort_test.go new file mode 100644 index 0000000..9cf5da6 --- /dev/null +++ b/array/sort/tim-sort/tim_sort_test.go @@ -0,0 +1,37 @@ +package sort + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_TimSort(t *testing.T) { + tt := []struct { + name string + array []int + expResult []int + }{ + { + name: "test_simple", + array: []int{12, 1, 20, 2, 3, 123, 54, 332}, + expResult: []int{1, 2, 3, 12, 20, 54, 123, 332}, + }, + { + name: "test_from_100_to_0", + array: []int{100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + expResult: []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100}, + }, + { + name: "test_all_cases", + array: []int{100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + expResult: []int{0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100}, + }, + } + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + TimSort(tc.array) + require.Equal(t, tc.expResult, tc.array) + }) + } +}