From 8a0b3175fd7b7f6bb4a7b196a8cc9ba4ec5b352c Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Sat, 19 Jul 2025 16:58:37 +0800 Subject: [PATCH 1/3] Add Recursive shuffling algorithm --- .../Shufflers/RecursiveShufflerTests.cs | 60 +++++++++++++++++++ Algorithms/Shufflers/RecursiveShuffler.cs | 35 +++++++++++ README.md | 1 + 3 files changed, 96 insertions(+) create mode 100644 Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs create mode 100644 Algorithms/Shufflers/RecursiveShuffler.cs diff --git a/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs b/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs new file mode 100644 index 00000000..28c86839 --- /dev/null +++ b/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs @@ -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(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray, testArray.Length - 1); + + // 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(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray, testArray.Length - 1); + + // 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(); + var (correctArray, testArray) = RandomHelper.GetArrays(n); + + // Act + shuffler.Shuffle(testArray, testArray.Length - 1, seed); + shuffler.Shuffle(correctArray, correctArray.Length - 1, seed); + + // Assert + correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering()); + } + } +} diff --git a/Algorithms/Shufflers/RecursiveShuffler.cs b/Algorithms/Shufflers/RecursiveShuffler.cs new file mode 100644 index 00000000..36f48d96 --- /dev/null +++ b/Algorithms/Shufflers/RecursiveShuffler.cs @@ -0,0 +1,35 @@ +using System; + +namespace Algorithms.Shufflers +{ + /// + /// Recursive Shuffler is a recursive version of + /// Fisher-Yates shuffle algorithm. This can only be used + /// for educational purposes due to stack depth limits. + /// + /// Type array input. + public class RecursiveShuffler + { + /// + /// First, it will check the length of the array on the base case. + /// Next, if there's still element left, it will shuffle the sub-array. + /// Lastly, it will randomly select index from 0 to length of array then + /// swap the elements array[arrayLength] and array[index]. + /// + /// Array to shuffle. + /// The length of the array. Used for terminator. + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int arrayLength, int? seed = null) + { + if(arrayLength <= 0) + { + return; + } + + Shuffle(array, arrayLength - 1, seed); + var random = seed is null ? new Random() : new Random(seed.Value); + int index = random.Next(arrayLength + 1); + (array[arrayLength], array[index]) = (array[index], array[arrayLength]); + } + } +} diff --git a/README.md b/README.md index bd8490d3..ff928316 100644 --- a/README.md +++ b/README.md @@ -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) From 00b9db0f42f6d437450f00ffb03a50f4ebb90900 Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Sun, 20 Jul 2025 09:44:50 +0800 Subject: [PATCH 2/3] Changed the parameter name of arrayLength to items --- Algorithms/Shufflers/RecursiveShuffler.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Algorithms/Shufflers/RecursiveShuffler.cs b/Algorithms/Shufflers/RecursiveShuffler.cs index 36f48d96..4820e5a3 100644 --- a/Algorithms/Shufflers/RecursiveShuffler.cs +++ b/Algorithms/Shufflers/RecursiveShuffler.cs @@ -12,24 +12,25 @@ public class RecursiveShuffler { /// /// First, it will check the length of the array on the base case. - /// Next, if there's still element left, it will shuffle the sub-array. - /// Lastly, it will randomly select index from 0 to length of array then - /// swap the elements array[arrayLength] and array[index]. + /// 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]. /// /// Array to shuffle. - /// The length of the array. Used for terminator. + /// Number of items in the array. /// Random generator seed. Used to repeat the shuffle. - public void Shuffle(T[] array, int arrayLength, int? seed = null) + public void Shuffle(T[] array, int items, int? seed = null) { - if(arrayLength <= 0) + if(items <= 0) { return; } - Shuffle(array, arrayLength - 1, seed); + Shuffle(array, items - 1, seed); var random = seed is null ? new Random() : new Random(seed.Value); - int index = random.Next(arrayLength + 1); - (array[arrayLength], array[index]) = (array[index], array[arrayLength]); + int index = random.Next(items + 1); + (array[items], array[index]) = (array[index], array[items]); + (array[items], array[index]) = (array[index], array[items]); } } } From 215c6fd135c093946f3391ac9fab270006f04b3b Mon Sep 17 00:00:00 2001 From: Jc Calayag <138150245+Jccqt@users.noreply.github.com> Date: Mon, 21 Jul 2025 20:20:17 +0800 Subject: [PATCH 3/3] Added public overload (array, seed) and private overload (array, items, seed) on RecursiveShuffler.cs. --- .../Shufflers/RecursiveShufflerTests.cs | 8 ++++---- Algorithms/Shufflers/RecursiveShuffler.cs | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs b/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs index 28c86839..0559e401 100644 --- a/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs +++ b/Algorithms.Tests/Shufflers/RecursiveShufflerTests.cs @@ -18,7 +18,7 @@ public static void ArrayShuffled_NewArraySameSize( var (correctArray, testArray) = RandomHelper.GetArrays(n); // Act - shuffler.Shuffle(testArray, testArray.Length - 1); + shuffler.Shuffle(testArray); // Assert testArray.Length.Should().Be(correctArray.Length); @@ -34,7 +34,7 @@ public static void ArrayShuffled_NewArraySameValues( var (correctArray, testArray) = RandomHelper.GetArrays(n); // Act - shuffler.Shuffle(testArray, testArray.Length - 1); + shuffler.Shuffle(testArray); // Assert testArray.Should().BeEquivalentTo(correctArray); @@ -50,8 +50,8 @@ public static void ArrayShuffled_NewArraySameShuffle( var (correctArray, testArray) = RandomHelper.GetArrays(n); // Act - shuffler.Shuffle(testArray, testArray.Length - 1, seed); - shuffler.Shuffle(correctArray, correctArray.Length - 1, seed); + shuffler.Shuffle(testArray, seed); + shuffler.Shuffle(correctArray, seed); // Assert correctArray.Should().BeEquivalentTo(testArray, options => options.WithStrictOrdering()); diff --git a/Algorithms/Shufflers/RecursiveShuffler.cs b/Algorithms/Shufflers/RecursiveShuffler.cs index 4820e5a3..4a367e1b 100644 --- a/Algorithms/Shufflers/RecursiveShuffler.cs +++ b/Algorithms/Shufflers/RecursiveShuffler.cs @@ -8,8 +8,18 @@ namespace Algorithms.Shufflers /// for educational purposes due to stack depth limits. /// /// Type array input. - public class RecursiveShuffler + public class RecursiveShuffler : IShuffler { + /// + /// This is the public overload method that calls the private overload method. + /// + /// Array to shuffle. + /// Random generator seed. Used to repeat the shuffle. + public void Shuffle(T[] array, int? seed = null) + { + Shuffle(array, array.Length - 1, seed); + } + /// /// 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. @@ -19,9 +29,9 @@ public class RecursiveShuffler /// Array to shuffle. /// Number of items in the array. /// Random generator seed. Used to repeat the shuffle. - public void Shuffle(T[] array, int items, int? seed = null) + private void Shuffle(T[] array, int items, int? seed) { - if(items <= 0) + if (items <= 0) { return; }