diff --git a/Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs b/Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs new file mode 100644 index 00000000..e86779fc --- /dev/null +++ b/Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs @@ -0,0 +1,60 @@ +using Algorithms.Sorters.Comparison; +using NUnit.Framework; +using System.Collections.Generic; + +namespace Algorithms.Tests.Sorters.Comparison +{ + [TestFixture] + public class BasicTimSorterTests + { + private BasicTimSorter sorter = new BasicTimSorter(Comparer.Default); + + [Test] + public void Sort_EmptyArray_DoesNotThrow() + { + var array = new int[] { }; + Assert.DoesNotThrow(() => sorter.Sort(array)); + Assert.That(array, Is.Empty); + } + + [Test] + public void Sort_SingleElementArray_DoesNotChangeArray() + { + var array = new[] { 1 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1 })); + } + + [Test] + public void Sort_AlreadySortedArray_DoesNotChangeArray() + { + var array = new[] { 1, 2, 3, 4, 5 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 })); + } + + [Test] + public void Sort_UnsortedArray_SortsCorrectly() + { + var array = new[] { 5, 3, 1, 4, 2 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 })); + } + + [Test] + public void Sort_ReverseSortedArray_SortsCorrectly() + { + var array = new[] { 5, 4, 3, 2, 1 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 })); + } + + [Test] + public void Sort_ArrayWithDuplicates_SortsCorrectly() + { + var array = new[] { 3, 1, 2, 3, 1, 2 }; + sorter.Sort(array); + Assert.That(array, Is.EqualTo(new[] { 1, 1, 2, 2, 3, 3 })); + } + } +} diff --git a/Algorithms/Sorters/Comparison/BasicTimSorter.cs b/Algorithms/Sorters/Comparison/BasicTimSorter.cs new file mode 100644 index 00000000..1a69eb7f --- /dev/null +++ b/Algorithms/Sorters/Comparison/BasicTimSorter.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Algorithms.Sorters.Comparison +{ + public class BasicTimSorter + { + private readonly int minRuns = 32; + private readonly IComparer comparer; + + public BasicTimSorter(IComparer comparer) + { + this.comparer = comparer ?? Comparer.Default; + } + + public void Sort(T[] array) + { + var n = array.Length; + + // Step 1: Sort small pieces of the array using Insertion Sort + for (var i = 0; i < n; i += minRuns) + { + InsertionSort(array, i, Math.Min(i + minRuns - 1, n - 1)); + } + + // Step 2: Merge sorted runs using Merge Sort + for (var size = minRuns; size < n; size *= 2) + { + for (var left = 0; left < n; left += 2 * size) + { + var mid = left + size - 1; + var right = Math.Min(left + 2 * size - 1, n - 1); + + if (mid < right) + { + Merge(array, left, mid, right); + } + } + } + } + + private void InsertionSort(T[] array, int left, int right) + { + for (var i = left + 1; i <= right; i++) + { + var key = array[i]; + var j = i - 1; + + while (j >= left && comparer.Compare(array[j], key) > 0) + { + array[j + 1] = array[j]; + j--; + } + + array[j + 1] = key; + } + } + + private void Merge(T[] array, int left, int mid, int right) + { + var leftSegment = new ArraySegment(array, left, mid - left + 1); + var rightSegment = new ArraySegment(array, mid + 1, right - mid); + + var leftArray = leftSegment.ToArray(); + var rightArray = rightSegment.ToArray(); + + int i = 0, j = 0, k = left; + + // Merge the two subarrays back into the main array + while (i < leftArray.Length && j < rightArray.Length) + { + if (comparer.Compare(leftArray[i], rightArray[j]) <= 0) + { + array[k++] = leftArray[i++]; + } + else + { + array[k++] = rightArray[j++]; + } + } + + // Copy remaining elements from leftArray, if any + while (i < leftArray.Length) + { + array[k++] = leftArray[i++]; + } + + // Copy remaining elements from rightArray, if any + while (j < rightArray.Length) + { + array[k++] = rightArray[j++]; + } + } + } +} diff --git a/README.md b/README.md index c66e20eb..2208ec72 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ find more than one implementation for the same objective but using different alg * [Selection Sort](./Algorithms/Sorters/Comparison/SelectionSorter.cs) * [Shell Sort](./Algorithms/Sorters/Comparison/ShellSorter.cs) * [Tim Sort](./Algorithms/Sorters/Comparison/TimSorter.cs) + * [Simplified Tim Sort](./Algorithms/Sorters/Comparison/BasicTimSorter.cs) * [External](./Algorithms/Sorters/External) * [Merge Sort](./Algorithms/Sorters/External/ExternalMergeSorter.cs) * [Integer](./Algorithms/Sorters/Integer)