Skip to content

Add Recursive shuffling algorithm #519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Algorithms.Shufflers;
using Algorithms.Tests.Helpers;
using FluentAssertions;
using NUnit.Framework;
using System;

namespace Algorithms.Tests.Shufflers
{
public static class RecursiveShufflerTests
{
[Test]
public static void ArrayShuffled_NewArraySameSize(
[Random(10, 1000, 100, Distinct = true)]
int n)
{
// Arrange
var shuffler = new RecursiveShuffler<int>();
var (correctArray, testArray) = RandomHelper.GetArrays(n);

// Act
shuffler.Shuffle(testArray);

// Assert
testArray.Length.Should().Be(correctArray.Length);
}

[Test]
public static void ArrayShuffled_NewArraySameValues(
[Random(10, 1000, 100, Distinct = true)]
int n)
{
// Arrange
var shuffler = new RecursiveShuffler<int>();
var (correctArray, testArray) = RandomHelper.GetArrays(n);

// Act
shuffler.Shuffle(testArray);

// Assert
testArray.Should().BeEquivalentTo(correctArray);
}

[Test]
public static void ArrayShuffled_NewArraySameShuffle(
[Random(0, 1000, 2, Distinct = true)] int n,
[Random(1000, 10000, 5, Distinct = true)] int seed)
{
// Arrange
var shuffler = new RecursiveShuffler<int>();
var (correctArray, testArray) = RandomHelper.GetArrays(n);

// Act
shuffler.Shuffle(testArray, seed);
shuffler.Shuffle(correctArray, seed);

// Assert
correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering());
}
}
}
46 changes: 46 additions & 0 deletions Algorithms/Shufflers/RecursiveShuffler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;

namespace Algorithms.Shufflers
{
/// <summary>
/// Recursive Shuffler is a recursive version of
/// Fisher-Yates shuffle algorithm. This can only be used
/// for educational purposes due to stack depth limits.
/// </summary>
/// <typeparam name="T">Type array input.</typeparam>
public class RecursiveShuffler<T> : IShuffler<T>
{
/// <summary>
/// This is the public overload method that calls the private overload method.
/// </summary>
/// <param name="array">Array to shuffle.</param>
/// <param name="seed">Random generator seed. Used to repeat the shuffle.</param>
public void Shuffle(T[] array, int? seed = null)
{
Shuffle(array, array.Length - 1, seed);
}

/// <summary>
/// First, it will check the length of the array on the base case.
/// Next, if there's still items left, it will shuffle the sub-array.
/// Lastly, it will randomly select index from 0 to number of items of the array
/// then swap the elements array[items] and array[index].
/// </summary>
/// <param name="array">Array to shuffle.</param>
/// <param name="items">Number of items in the array.</param>
/// <param name="seed">Random generator seed. Used to repeat the shuffle.</param>
private void Shuffle(T[] array, int items, int? seed)
{
if (items <= 0)
{
return;
}

Shuffle(array, items - 1, seed);
var random = seed is null ? new Random() : new Random(seed.Value);
int index = random.Next(items + 1);
(array[items], array[index]) = (array[index], array[items]);
(array[items], array[index]) = (array[index], array[items]);
}
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ find more than one implementation for the same objective but using different alg
* [Fisher-Yates Shuffler](./Algorithms/Shufflers/FisherYatesShuffler.cs)
* [LINQ Shuffler](./Algorithms/Shufflers/LinqShuffler.cs)
* [Naive Shuffler](./Algorithms/Shufflers/NaiveShuffler.cs)
* [Recursive Shuffler](./Algorithms/Shufflers/RecursiveShuffler.cs)
* [Sequences](./Algorithms/Sequences)
* [A000002 Kolakoski](./Algorithms/Sequences/KolakoskiSequence.cs)
* [A000004 Zero](./Algorithms/Sequences/ZeroSequence.cs)
Expand Down