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) + }) + } +}