diff --git a/csharp-algorithms/RadixSort/RadixSort/Program.cs b/csharp-algorithms/RadixSort/RadixSort/Program.cs index f9f6c68496..8b080ff66a 100644 --- a/csharp-algorithms/RadixSort/RadixSort/Program.cs +++ b/csharp-algorithms/RadixSort/RadixSort/Program.cs @@ -1,4 +1,4 @@ using BenchmarkDotNet.Running; using RadixSort; -var summary = BenchmarkRunner.Run(); \ No newline at end of file +BenchmarkRunner.Run(args: args); diff --git a/csharp-algorithms/RadixSort/RadixSort/RadixSort.csproj b/csharp-algorithms/RadixSort/RadixSort/RadixSort.csproj index 6103222f24..c96a8eb1e7 100644 --- a/csharp-algorithms/RadixSort/RadixSort/RadixSort.csproj +++ b/csharp-algorithms/RadixSort/RadixSort/RadixSort.csproj @@ -2,13 +2,13 @@ Exe - net6.0 + net10.0 enable enable - + diff --git a/csharp-algorithms/RadixSort/RadixSort/RadixSortBenchmarks.cs b/csharp-algorithms/RadixSort/RadixSort/RadixSortBenchmarks.cs new file mode 100644 index 0000000000..da23fd12ca --- /dev/null +++ b/csharp-algorithms/RadixSort/RadixSort/RadixSortBenchmarks.cs @@ -0,0 +1,43 @@ +using BenchmarkDotNet.Attributes; + +namespace RadixSort; + +public class RadixSortBenchmarks +{ + private readonly RadixSortMethods _radix = new(); + private int[] _source = []; + private int[] _work = []; + + [Params("Random", "Sorted", "Imbalanced")] + public string Input { get; set; } = "Random"; + + [GlobalSetup] + public void Setup() + { + _source = Input switch + { + "Sorted" => RadixSortMethods.CreateSortedArray(20000), + "Imbalanced" => RadixSortMethods.CreateImbalancedArray( + RadixSortMethods.CreateRandomArray(19999, 10000, 30000)), + _ => RadixSortMethods.CreateRandomArray(20000, 10000, 30000) + }; + _work = new int[_source.Length]; + } + + [Benchmark(Baseline = true)] + public int[] RadixSort() + { + _source.CopyTo(_work, 0); + + return _radix.RadixSort(_work, _work.Length); + } + + [Benchmark] + public int[] ArraySort() + { + _source.CopyTo(_work, 0); + Array.Sort(_work); + + return _work; + } +} diff --git a/csharp-algorithms/RadixSort/RadixSort/RadixSortMethods.cs b/csharp-algorithms/RadixSort/RadixSort/RadixSortMethods.cs index 8503169af9..505e3d9830 100644 --- a/csharp-algorithms/RadixSort/RadixSort/RadixSortMethods.cs +++ b/csharp-algorithms/RadixSort/RadixSort/RadixSortMethods.cs @@ -1,93 +1,108 @@ -using BenchmarkDotNet.Attributes; +namespace RadixSort; -namespace RadixSort +public class RadixSortMethods { - public class RadixSortMethods + public int[] RadixSort(int[] array, int size) { - public IEnumerable SampleArrays() - { - yield return new object[] { CreateRandomArray(20000, 10000, 30000), 20000, "Best Case" }; - yield return new object[] { CreateSortedArray(20000), 20000, "Average Case" }; - yield return new object[] { CreateImbalancedArray(CreateRandomArray(19999, 10000, 30000)), 20000, "Worst Case" }; - } + if (size == 0) + return array; - [Benchmark] - [ArgumentsSource(nameof(SampleArrays))] - public int[] RadixSort (int[] array, int size, string arrayName) - { - var maxVal = GetMaxVal(array, size); + var maxVal = GetMaxVal(array, size); + + for (long exponent = 1; maxVal / exponent > 0; exponent *= 10) + CountingSort(array, size, exponent); - for (int exponent = 1; maxVal / exponent > 0; exponent *= 10) - CountingSort(array, size, exponent); + return array; + } + public int[] RadixSortWithNegatives(int[] array, int size) + { + if (size == 0) return array; - } - public static int GetMaxVal(int[] array, int size) - { - var maxVal = array[0]; + var minVal = GetMinVal(array, size); - for (int i = 1; i < size; i++) - if (array[i] > maxVal) - maxVal = array[i]; + if (minVal >= 0) + return RadixSort(array, size); - return maxVal; - } + for (int i = 0; i < size; i++) + array[i] = checked(array[i] - minVal); - public static void CountingSort(int[] array, int size, int exponent) - { - var outputArr = new int[size]; - var occurences = new int[10]; + RadixSort(array, size); - for (int i = 0; i < 10; i++) - occurences[i] = 0; + for (int i = 0; i < size; i++) + array[i] += minVal; - for (int i = 0; i < size; i++) - occurences[(array[i] / exponent) % 10]++; + return array; + } - for (int i = 1; i < 10; i++) - occurences[i] += occurences[i - 1]; + public static int GetMaxVal(int[] array, int size) + { + var maxVal = array[0]; - for (int i = size - 1; i >= 0; i--) - { - outputArr[occurences[(array[i] / exponent) % 10] - 1] = array[i]; - occurences[(array[i] / exponent) % 10]--; - } + for (int i = 1; i < size; i++) + if (array[i] > maxVal) + maxVal = array[i]; - for (int i = 0; i < size; i++) - array[i] = outputArr[i]; - } + return maxVal; + } - public static int[] CreateRandomArray(int size, int lower, int upper) - { - var array = new int[size]; - var rand = new Random(); + public static int GetMinVal(int[] array, int size) + { + var minVal = array[0]; - for (int i = 0; i < size; i++) - array[i] = rand.Next(lower, upper); + for (int i = 1; i < size; i++) + if (array[i] < minVal) + minVal = array[i]; - return array; - } + return minVal; + } - public static int[] CreateSortedArray(int size) - { - var array = new int[size]; + public static void CountingSort(int[] array, int size, long exponent) + { + var outputArr = new int[size]; + var occurrences = new int[10]; - for (int i = 0; i < size; i++) - array[i] = i; + for (int i = 0; i < size; i++) + occurrences[(array[i] / exponent) % 10]++; - return array; - } + for (int i = 1; i < 10; i++) + occurrences[i] += occurrences[i - 1]; - public static int[] CreateImbalancedArray(int[] array) + for (int i = size - 1; i >= 0; i--) { - List numbers = new List(); + outputArr[occurrences[(array[i] / exponent) % 10] - 1] = array[i]; + occurrences[(array[i] / exponent) % 10]--; + } - numbers.AddRange(array); - numbers.Add(Int32.MaxValue); + for (int i = 0; i < size; i++) + array[i] = outputArr[i]; + } - return numbers.ToArray(); - } + public static int[] CreateRandomArray(int size, int lower, int upper) + { + var array = new int[size]; + + for (int i = 0; i < size; i++) + array[i] = Random.Shared.Next(lower, upper); + + return array; + } + + public static int[] CreateSortedArray(int size) + { + var array = new int[size]; + + for (int i = 0; i < size; i++) + array[i] = i; + + return array; + } + + public static int[] CreateImbalancedArray(int[] array) + { + List numbers = [.. array, int.MaxValue]; + return numbers.ToArray(); } } diff --git a/csharp-algorithms/RadixSort/RadixSortTests/RadixSortTests.csproj b/csharp-algorithms/RadixSort/RadixSortTests/RadixSortTests.csproj index 89ea34433b..426d393c66 100644 --- a/csharp-algorithms/RadixSort/RadixSortTests/RadixSortTests.csproj +++ b/csharp-algorithms/RadixSort/RadixSortTests/RadixSortTests.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 enable enable @@ -9,10 +9,10 @@ - - - - + + + + diff --git a/csharp-algorithms/RadixSort/RadixSortTests/RadixSortUnitTests.cs b/csharp-algorithms/RadixSort/RadixSortTests/RadixSortUnitTests.cs index 226a2e2013..68899b9bc0 100644 --- a/csharp-algorithms/RadixSort/RadixSortTests/RadixSortUnitTests.cs +++ b/csharp-algorithms/RadixSort/RadixSortTests/RadixSortUnitTests.cs @@ -1,56 +1,127 @@ using RadixSort; -namespace RadixSortTests +namespace RadixSortTests; + +[TestClass] +public class RadixSortUnitTests { - [TestClass] - public class RadixSortUnitTests + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsNotEmpty_ThenReturnSortedArray() + { + var array = new int[] { 73, 57, 49, 99, 133, 20, 1 }; + var expected = new int[] { 1, 20, 49, 57, 73, 99, 133 }; + var sortFunction = new RadixSortMethods(); + + var sortedArray = sortFunction.RadixSort(array, array.Length); + + Assert.IsNotNull(sortedArray); + CollectionAssert.AreEqual(expected, sortedArray); + } + + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsRandomized_ThenCheckInstanceType() + { + var sortFunction = new RadixSortMethods(); + var array = RadixSortMethods.CreateRandomArray(200, 0, 200); + + var sortedArray = sortFunction.RadixSort(array, array.Length); + + Assert.IsInstanceOfType(sortedArray, typeof(int[])); + } + + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsSorted_ThenResultingArrayIsNotNull() + { + var sortFunction = new RadixSortMethods(); + var array = RadixSortMethods.CreateRandomArray(200, 0, 200); + + var sortedArray = sortFunction.RadixSort(array, array.Length); + + Assert.IsNotNull(sortedArray); + } + + [TestMethod] + public void GivenArray_WhenArrayHasSingleElement_ThenReturnSortedArray() + { + var array = new int[] { 73 }; + var expected = new int[] { 73 }; + var sortFunction = new RadixSortMethods(); + + var sortedArray = sortFunction.RadixSort(array, array.Length); + + Assert.IsNotNull(sortedArray); + CollectionAssert.AreEqual(expected, sortedArray); + } + + [TestMethod] + public void GivenEmptyArray_WhenSorted_ThenReturnEmptyArray() { - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsNotEmpty_ThenReturnSortedArray() - { - var array = new int[] { 73, 57, 49, 99, 133, 20, 1 }; - var expected = new int[] { 1, 20, 49, 57, 73, 99, 133 }; - var sortFunction = new RadixSortMethods(); + var sortFunction = new RadixSortMethods(); + + var sortedArray = sortFunction.RadixSort([], 0); + + Assert.IsEmpty(sortedArray); + } + + [TestMethod] + public void GivenRandomArrayWithDuplicates_WhenSorted_ThenMatchesArraySort() + { + var sortFunction = new RadixSortMethods(); + var array = RadixSortMethods.CreateRandomArray(1000, 0, 50); + var expected = (int[])array.Clone(); + Array.Sort(expected); + + var sortedArray = sortFunction.RadixSort(array, array.Length); - var sortedArray = sortFunction.RadixSort(array, array.Length, string.Empty); + CollectionAssert.AreEqual(expected, sortedArray); + } - Assert.IsNotNull(sortedArray); - CollectionAssert.AreEqual(sortedArray, expected); - } + [TestMethod] + public void GivenSortedArray_WhenSorted_ThenStaysSorted() + { + var sortFunction = new RadixSortMethods(); + var array = RadixSortMethods.CreateSortedArray(500); + var expected = (int[])array.Clone(); - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsRandomized_ThenCheckInstanceType() - { - var sortFunction = new RadixSortMethods(); - var array = RadixSortMethods.CreateRandomArray(200, 0, 200); + var sortedArray = sortFunction.RadixSort(array, array.Length); - var sortedArray = sortFunction.RadixSort(array, array.Length, string.Empty); + CollectionAssert.AreEqual(expected, sortedArray); + } - Assert.IsInstanceOfType(sortedArray, typeof(int[])); - } + [TestMethod] + public void GivenArrayWithIntMaxValue_WhenSorted_ThenMatchesArraySort() + { + var sortFunction = new RadixSortMethods(); + var array = RadixSortMethods.CreateImbalancedArray( + RadixSortMethods.CreateRandomArray(999, 10000, 30000)); + var expected = (int[])array.Clone(); + Array.Sort(expected); - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsSorted_ThenResultingArrayIsNotNull() - { - var sortFunction = new RadixSortMethods(); ; - var array = RadixSortMethods.CreateRandomArray(200, 0, 200); + var sortedArray = sortFunction.RadixSort(array, array.Length); - var sortedArray = sortFunction.RadixSort(array, array.Length, string.Empty); + CollectionAssert.AreEqual(expected, sortedArray); + } - Assert.IsNotNull(sortedArray); - } + [TestMethod] + public void GivenArrayWithNegativeNumbers_WhenSortedWithNegatives_ThenMatchesArraySort() + { + var sortFunction = new RadixSortMethods(); + var array = RadixSortMethods.CreateRandomArray(1000, -5000, 5000); + var expected = (int[])array.Clone(); + Array.Sort(expected); + + var sortedArray = sortFunction.RadixSortWithNegatives(array, array.Length); - [TestMethod] - public void GivenArray_WhenArrayHasSingleElement_ThenReturnSortedArray() - { - var array = new int[] { 73 }; - var expected = new int[] { 73 }; - var sortFunction = new RadixSortMethods(); + CollectionAssert.AreEqual(expected, sortedArray); + } - var sortedArray = sortFunction.RadixSort(array, array.Length, string.Empty); + [TestMethod] + public void GivenRangeWiderThanInt_WhenSortedWithNegatives_ThenThrowsOverflowException() + { + var sortFunction = new RadixSortMethods(); + var array = new int[] { int.MaxValue, 0, int.MinValue }; - Assert.IsNotNull(sortedArray); - CollectionAssert.AreEqual(sortedArray, expected); - } + Assert.ThrowsExactly( + () => sortFunction.RadixSortWithNegatives(array, array.Length)); } -} \ No newline at end of file +}