Skip to content

Commit cf19352

Browse files
authored
Add Basic TimSorter (#471)
1 parent ab2b5cc commit cf19352

File tree

3 files changed

+208
-0
lines changed

3 files changed

+208
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using Algorithms.Sorters.Comparison;
2+
using FluentAssertions;
3+
using NUnit.Framework;
4+
using System;
5+
using System.Collections.Generic;
6+
7+
namespace Algorithms.Tests.Sorters.Comparison
8+
{
9+
[TestFixture]
10+
public class BasicTimSorterTests
11+
{
12+
private readonly BasicTimSorter<int> sorter = new(Comparer<int>.Default);
13+
14+
[Test]
15+
public void Sort_EmptyArray_DoesNotThrow()
16+
{
17+
var array = Array.Empty<int>();
18+
Assert.DoesNotThrow(() => sorter.Sort(array));
19+
Assert.That(array, Is.Empty);
20+
}
21+
22+
[Test]
23+
public void Sort_SingleElementArray_DoesNotChangeArray()
24+
{
25+
var array = new[] { 1 };
26+
sorter.Sort(array);
27+
Assert.That(array, Is.EqualTo(new[] { 1 }));
28+
}
29+
30+
[Test]
31+
public void Sort_AlreadySortedArray_DoesNotChangeArray()
32+
{
33+
var array = new[] { 1, 2, 3, 4, 5 };
34+
sorter.Sort(array);
35+
Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));
36+
}
37+
38+
[Test]
39+
public void Sort_UnsortedArray_SortsCorrectly()
40+
{
41+
var array = new[] { 5, 3, 1, 4, 2 };
42+
sorter.Sort(array);
43+
Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));
44+
}
45+
46+
[Test]
47+
public void Sort_ReverseSortedArray_SortsCorrectly()
48+
{
49+
var array = new[] { 5, 4, 3, 2, 1 };
50+
sorter.Sort(array);
51+
Assert.That(array, Is.EqualTo(new[] { 1, 2, 3, 4, 5 }));
52+
}
53+
54+
[Test]
55+
public void Sort_ArrayWithDuplicates_SortsCorrectly()
56+
{
57+
var array = new[] { 3, 1, 2, 3, 1, 2 };
58+
sorter.Sort(array);
59+
Assert.That(array, Is.EqualTo(new[] { 1, 1, 2, 2, 3, 3 }));
60+
}
61+
62+
[Test]
63+
public void Sort_LargeArray_SortsCorrectly()
64+
{
65+
var array = new int[1000];
66+
for (var i = 0; i < 1000; i++)
67+
{
68+
array[i] = 1000 - i;
69+
}
70+
sorter.Sort(array);
71+
array.Should().BeInAscendingOrder();
72+
}
73+
74+
[Test]
75+
public void Sort_LargeRandomArray_SortsCorrectly()
76+
{
77+
var array = new int[1000];
78+
var random = new Random();
79+
for (var i = 0; i < 1000; i++)
80+
{
81+
array[i] = random.Next(1, 1001);
82+
}
83+
sorter.Sort(array);
84+
array.Should().BeInAscendingOrder();
85+
}
86+
}
87+
}

Diff for: Algorithms/Sorters/Comparison/BasicTimSorter.cs

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
5+
namespace Algorithms.Sorters.Comparison
6+
{
7+
/// <summary>
8+
/// A basic implementation of the TimSort algorithm for sorting arrays.
9+
/// </summary>
10+
/// <typeparam name="T">The type of elements in the array.</typeparam>
11+
public class BasicTimSorter<T>
12+
{
13+
private readonly int minRuns = 32;
14+
private readonly IComparer<T> comparer;
15+
16+
/// <summary>
17+
/// Initializes a new instance of the <see cref="BasicTimSorter{T}"/> class.
18+
/// </summary>
19+
/// <param name="comparer">The comparer to use for comparing elements.</param>
20+
public BasicTimSorter(IComparer<T> comparer)
21+
{
22+
this.comparer = comparer ?? Comparer<T>.Default;
23+
}
24+
25+
/// <summary>
26+
/// Sorts the specified array using the TimSort algorithm.
27+
/// </summary>
28+
/// <param name="array">The array to sort.</param>
29+
public void Sort(T[] array)
30+
{
31+
var n = array.Length;
32+
33+
// Step 1: Sort small pieces of the array using Insertion Sort
34+
for (var i = 0; i < n; i += minRuns)
35+
{
36+
InsertionSort(array, i, Math.Min(i + minRuns - 1, n - 1));
37+
}
38+
39+
// Step 2: Merge sorted runs using Merge Sort
40+
for (var size = minRuns; size < n; size *= 2)
41+
{
42+
for (var left = 0; left < n; left += 2 * size)
43+
{
44+
var mid = left + size - 1;
45+
var right = Math.Min(left + 2 * size - 1, n - 1);
46+
47+
if (mid < right)
48+
{
49+
Merge(array, left, mid, right);
50+
}
51+
}
52+
}
53+
}
54+
55+
/// <summary>
56+
/// Sorts a portion of the array using the Insertion Sort algorithm.
57+
/// </summary>
58+
/// <param name="array">The array to sort.</param>
59+
/// <param name="left">The starting index of the portion to sort.</param>
60+
/// <param name="right">The ending index of the portion to sort.</param>
61+
private void InsertionSort(T[] array, int left, int right)
62+
{
63+
for (var i = left + 1; i <= right; i++)
64+
{
65+
var key = array[i];
66+
var j = i - 1;
67+
68+
// Move elements of array[0..i-1], that are greater than key,
69+
// to one position ahead of their current position
70+
while (j >= left && comparer.Compare(array[j], key) > 0)
71+
{
72+
array[j + 1] = array[j];
73+
j--;
74+
}
75+
76+
array[j + 1] = key;
77+
}
78+
}
79+
80+
/// <summary>
81+
/// Merges two sorted subarrays into a single sorted subarray.
82+
/// </summary>
83+
/// <param name="array">The array containing the subarrays to merge.</param>
84+
/// <param name="left">The starting index of the first subarray.</param>
85+
/// <param name="mid">The ending index of the first subarray.</param>
86+
/// <param name="right">The ending index of the second subarray.</param>
87+
private void Merge(T[] array, int left, int mid, int right)
88+
{
89+
// Create segments for left and right subarrays
90+
var leftSegment = new ArraySegment<T>(array, left, mid - left + 1);
91+
var rightSegment = new ArraySegment<T>(array, mid + 1, right - mid);
92+
93+
// Convert segments to arrays
94+
var leftArray = leftSegment.ToArray();
95+
var rightArray = rightSegment.ToArray();
96+
97+
var i = 0;
98+
var j = 0;
99+
var k = left;
100+
101+
// Merge the two subarrays back into the main array
102+
while (i < leftArray.Length && j < rightArray.Length)
103+
{
104+
array[k++] = comparer.Compare(leftArray[i], rightArray[j]) <= 0 ? leftArray[i++] : rightArray[j++];
105+
}
106+
107+
// Copy remaining elements from leftArray, if any
108+
while (i < leftArray.Length)
109+
{
110+
array[k++] = leftArray[i++];
111+
}
112+
113+
// Copy remaining elements from rightArray, if any
114+
while (j < rightArray.Length)
115+
{
116+
array[k++] = rightArray[j++];
117+
}
118+
}
119+
}
120+
}

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ find more than one implementation for the same objective but using different alg
126126
* [Selection Sort](./Algorithms/Sorters/Comparison/SelectionSorter.cs)
127127
* [Shell Sort](./Algorithms/Sorters/Comparison/ShellSorter.cs)
128128
* [Tim Sort](./Algorithms/Sorters/Comparison/TimSorter.cs)
129+
* [Simplified Tim Sort](./Algorithms/Sorters/Comparison/BasicTimSorter.cs)
129130
* [External](./Algorithms/Sorters/External)
130131
* [Merge Sort](./Algorithms/Sorters/External/ExternalMergeSorter.cs)
131132
* [Integer](./Algorithms/Sorters/Integer)

0 commit comments

Comments
 (0)