Skip to content

Commit

Permalink
Add Basic TimSorter (#471)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kalkwst authored Sep 24, 2024
1 parent ab2b5cc commit cf19352
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 0 deletions.
87 changes: 87 additions & 0 deletions Algorithms.Tests/Sorters/Comparison/BasicTeamSorterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Algorithms.Sorters.Comparison;
using FluentAssertions;
using NUnit.Framework;
using System;
using System.Collections.Generic;

namespace Algorithms.Tests.Sorters.Comparison
{
[TestFixture]
public class BasicTimSorterTests
{
private readonly BasicTimSorter<int> sorter = new(Comparer<int>.Default);

[Test]
public void Sort_EmptyArray_DoesNotThrow()
{
var array = Array.Empty<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 }));
}

[Test]
public void Sort_LargeArray_SortsCorrectly()
{
var array = new int[1000];
for (var i = 0; i < 1000; i++)
{
array[i] = 1000 - i;
}
sorter.Sort(array);
array.Should().BeInAscendingOrder();
}

[Test]
public void Sort_LargeRandomArray_SortsCorrectly()
{
var array = new int[1000];
var random = new Random();
for (var i = 0; i < 1000; i++)
{
array[i] = random.Next(1, 1001);
}
sorter.Sort(array);
array.Should().BeInAscendingOrder();
}
}
}
120 changes: 120 additions & 0 deletions Algorithms/Sorters/Comparison/BasicTimSorter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace Algorithms.Sorters.Comparison
{
/// <summary>
/// A basic implementation of the TimSort algorithm for sorting arrays.
/// </summary>
/// <typeparam name="T">The type of elements in the array.</typeparam>
public class BasicTimSorter<T>
{
private readonly int minRuns = 32;
private readonly IComparer<T> comparer;

/// <summary>
/// Initializes a new instance of the <see cref="BasicTimSorter{T}"/> class.
/// </summary>
/// <param name="comparer">The comparer to use for comparing elements.</param>
public BasicTimSorter(IComparer<T> comparer)
{
this.comparer = comparer ?? Comparer<T>.Default;
}

/// <summary>
/// Sorts the specified array using the TimSort algorithm.
/// </summary>
/// <param name="array">The array to sort.</param>
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);
}
}
}
}

/// <summary>
/// Sorts a portion of the array using the Insertion Sort algorithm.
/// </summary>
/// <param name="array">The array to sort.</param>
/// <param name="left">The starting index of the portion to sort.</param>
/// <param name="right">The ending index of the portion to sort.</param>
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;

// Move elements of array[0..i-1], that are greater than key,
// to one position ahead of their current position
while (j >= left && comparer.Compare(array[j], key) > 0)
{
array[j + 1] = array[j];
j--;
}

array[j + 1] = key;
}
}

/// <summary>
/// Merges two sorted subarrays into a single sorted subarray.
/// </summary>
/// <param name="array">The array containing the subarrays to merge.</param>
/// <param name="left">The starting index of the first subarray.</param>
/// <param name="mid">The ending index of the first subarray.</param>
/// <param name="right">The ending index of the second subarray.</param>
private void Merge(T[] array, int left, int mid, int right)
{
// Create segments for left and right subarrays
var leftSegment = new ArraySegment<T>(array, left, mid - left + 1);
var rightSegment = new ArraySegment<T>(array, mid + 1, right - mid);

// Convert segments to arrays
var leftArray = leftSegment.ToArray();
var rightArray = rightSegment.ToArray();

var i = 0;
var j = 0;
var k = left;

// Merge the two subarrays back into the main array
while (i < leftArray.Length && j < rightArray.Length)
{
array[k++] = comparer.Compare(leftArray[i], rightArray[j]) <= 0 ? leftArray[i++] : 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++];
}
}
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,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)
Expand Down

0 comments on commit cf19352

Please sign in to comment.