From ed00c7f31ffaea02a4f72d3a580d7c6deed6476c Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Sun, 8 Nov 2026 18:25:19 +0100 Subject: [PATCH] Insertion sort: move to .NET 10, benchmark a fresh copy per call Both projects target net10.0 with BenchmarkDotNet 0.15.8, MSTest 4.5.2, Microsoft.NET.Test.Sdk 18.11.0 and coverlet.collector 10.1.0. The benchmark moves to its own InsertionSortBenchmarks class that copies a never-sorted source array into a working array on every call, so random and reversed rows no longer measure already-sorted data. The sort methods lose the benchmark-only arrayName parameter and now match the article. Tests use (expected, actual) order and a new data-driven test compares both versions with Array.Sort. --- .../InsertionSort/InsertionSort.csproj | 4 +- .../InsertionSort/InsertionSortBenchmarks.cs | 45 +++++++ .../InsertionSort/InsertionSortMethods.cs | 124 +++++++---------- .../InsertionSort/InsertionSort/Program.cs | 2 +- .../InsertionSortTests.csproj | 15 ++- .../InsertionSortUnitTests.cs | 126 +++++++++++------- 6 files changed, 184 insertions(+), 132 deletions(-) create mode 100644 csharp-algorithms/InsertionSort/InsertionSort/InsertionSortBenchmarks.cs diff --git a/csharp-algorithms/InsertionSort/InsertionSort/InsertionSort.csproj b/csharp-algorithms/InsertionSort/InsertionSort/InsertionSort.csproj index 79e7148fd0..62be4f867f 100644 --- a/csharp-algorithms/InsertionSort/InsertionSort/InsertionSort.csproj +++ b/csharp-algorithms/InsertionSort/InsertionSort/InsertionSort.csproj @@ -2,13 +2,13 @@ Exe - net6.0 + net10.0 enable enable - + diff --git a/csharp-algorithms/InsertionSort/InsertionSort/InsertionSortBenchmarks.cs b/csharp-algorithms/InsertionSort/InsertionSort/InsertionSortBenchmarks.cs new file mode 100644 index 0000000000..3a8a890bcd --- /dev/null +++ b/csharp-algorithms/InsertionSort/InsertionSort/InsertionSortBenchmarks.cs @@ -0,0 +1,45 @@ +using BenchmarkDotNet.Attributes; + +namespace InsertionSort; + +public class InsertionSortBenchmarks +{ + private readonly InsertionSortMethods _sortFunction = new(); + private int[] _source = []; + private int[] _work = []; + + [Params(100, 1_000, 10_000)] + public int Size { get; set; } + + [Params("Random", "Sorted", "Reversed")] + public string Input { get; set; } = "Random"; + + [GlobalSetup] + public void Setup() + { + _source = Input switch + { + "Sorted" => InsertionSortMethods.CreateSortedArray(Size), + "Reversed" => InsertionSortMethods.CreateReversedArray( + InsertionSortMethods.CreateSortedArray(Size)), + _ => InsertionSortMethods.CreateRandomArray(Size) + }; + _work = new int[Size]; + } + + [Benchmark] + public int[] SortArray() + { + _source.CopyTo(_work, 0); + + return _sortFunction.SortArray(_work, _work.Length); + } + + [Benchmark] + public int[] SortArrayRecursive() + { + _source.CopyTo(_work, 0); + + return _sortFunction.SortArrayRecursive(_work, _work.Length); + } +} diff --git a/csharp-algorithms/InsertionSort/InsertionSort/InsertionSortMethods.cs b/csharp-algorithms/InsertionSort/InsertionSort/InsertionSortMethods.cs index a98d9cd81e..747ad3c9bc 100644 --- a/csharp-algorithms/InsertionSort/InsertionSort/InsertionSortMethods.cs +++ b/csharp-algorithms/InsertionSort/InsertionSort/InsertionSortMethods.cs @@ -1,100 +1,76 @@ -using BenchmarkDotNet.Attributes; +namespace InsertionSort; -namespace InsertionSort +public class InsertionSortMethods { - public class InsertionSortMethods + public int[] SortArray(int[] array, int length) { - public IEnumerable SampleArrays() + for (int i = 1; i < length; i++) { - yield return new object[] { CreateRandomArray(200), 200, "Small Unsorted" }; - yield return new object[] { CreateRandomArray(2000), 2000, "Medium Unsorted" }; - yield return new object[] { CreateRandomArray(20000), 20000, "Large Unsorted" }; - yield return new object[] { CreateSortedArray(200), 200, "Small Sorted" }; - yield return new object[] { CreateSortedArray(2000), 2000, "Medium Sorted" }; - yield return new object[] { CreateSortedArray(20000), 20000, "Large Sorted" }; - yield return new object[] { CreateReversedArray(CreateSortedArray(200)), 200, "Small Reversed" }; - yield return new object[] { CreateReversedArray(CreateSortedArray(2000)), 2000, "Medium Reversed" }; - yield return new object[] { CreateReversedArray(CreateSortedArray(20000)), 20000, "Large Reversed" }; - } - - [Benchmark] - [ArgumentsSource(nameof(SampleArrays))] - public int[] SortArray(int[] array, int length, string arrayName) - { - if (length <= 1) - { - return array; - } + var key = array[i]; + var flag = 0; - for (int i = 1; i < length; i++) + for (int j = i - 1; j >= 0 && flag != 1;) { - var key = array[i]; - var flag = 0; - - for (int j = i - 1; j >= 0 && flag != 1;) + if (key < array[j]) { - if (key < array[j]) - { - array[j + 1] = array[j]; - j--; - array[j + 1] = key; - } - else flag = 1; + array[j + 1] = array[j]; + j--; + array[j + 1] = key; } + else flag = 1; } + } + + return array; + } + public int[] SortArrayRecursive(int[] array, int length) + { + if (length <= 1) + { return array; } - [Benchmark] - [ArgumentsSource(nameof(SampleArrays))] - public int[] SortArrayRecursive(int[] array, int length, string arrayName) - { - if (length <= 1) - { - return array; - } + SortArrayRecursive(array, length - 1); + var key = array[length - 1]; + var k = length - 2; - SortArrayRecursive(array, length - 1, arrayName); - var key = array[length - 1]; - var k = length - 2; + while (k >= 0 && array[k] > key) + { + array[k + 1] = array[k]; + k = k - 1; + } - while (k >= 0 && array[k] > key) - { - array[k + 1] = array[k]; - k = k - 1; - } + array[k + 1] = key; - array[k + 1] = key; + return array; + } - return array; - } - public static int[] CreateRandomArray(int size) - { - var array = new int[size]; - var rand = new Random(); + public static int[] CreateRandomArray(int size) + { + var array = new int[size]; + var rand = new Random(); - for (int i = 0; i < size; i++) - array[i] = rand.Next(); + for (int i = 0; i < size; i++) + array[i] = rand.Next(); - return array; - } + return array; + } - public static int[] CreateSortedArray(int size) - { - var array = new int[size]; + public static int[] CreateSortedArray(int size) + { + var array = new int[size]; - for (int i = 0; i < size; i++) - array[i] = i; + for (int i = 0; i < size; i++) + array[i] = i; - return array; - } + return array; + } - public static int[] CreateReversedArray(int[] array) - { - Array.Reverse(array); + public static int[] CreateReversedArray(int[] array) + { + Array.Reverse(array); - return array; - } + return array; } } diff --git a/csharp-algorithms/InsertionSort/InsertionSort/Program.cs b/csharp-algorithms/InsertionSort/InsertionSort/Program.cs index 933c6df993..9a2a6999cb 100644 --- a/csharp-algorithms/InsertionSort/InsertionSort/Program.cs +++ b/csharp-algorithms/InsertionSort/InsertionSort/Program.cs @@ -1,4 +1,4 @@ using BenchmarkDotNet.Running; using InsertionSort; -var summary = BenchmarkRunner.Run(); \ No newline at end of file +BenchmarkRunner.Run(args: args); diff --git a/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortTests.csproj b/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortTests.csproj index 5380ab5695..d175391685 100644 --- a/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortTests.csproj +++ b/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortTests.csproj @@ -1,22 +1,27 @@ - net6.0 + net10.0 + enable enable false - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortUnitTests.cs b/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortUnitTests.cs index 1fdffb2c09..f819d0985a 100644 --- a/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortUnitTests.cs +++ b/csharp-algorithms/InsertionSort/InsertionSortTests/InsertionSortUnitTests.cs @@ -1,70 +1,96 @@ using InsertionSort; -using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace InsertionSortTests +namespace InsertionSortTests; + +[TestClass] +public class InsertionSortUnitTests { - [TestClass] - public class InsertionSortUnitTests + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsNotEmpty_ThenReturnSortedArray() { - [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 InsertionSortMethods(); + 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 InsertionSortMethods(); - var sortedArray = sortFunction.SortArray(array, array.Length, string.Empty); + var sortedArray = sortFunction.SortArray(array, array.Length); - Assert.IsNotNull(sortedArray); - CollectionAssert.AreEqual(sortedArray, expected); - } + Assert.IsNotNull(sortedArray); + CollectionAssert.AreEqual(expected, sortedArray); + } - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsRandomized_ThenCheckInstanceType() - { - var sortFunction = new InsertionSortMethods(); ; - var array = InsertionSortMethods.CreateRandomArray(200); + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsRandomized_ThenCheckInstanceType() + { + var sortFunction = new InsertionSortMethods(); + var array = InsertionSortMethods.CreateRandomArray(200); - var sortedArray = sortFunction.SortArray(array, array.Length, string.Empty); + var sortedArray = sortFunction.SortArray(array, array.Length); - Assert.IsInstanceOfType(sortedArray, typeof(int[])); - } + Assert.IsInstanceOfType(sortedArray); + } - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsSorted_ThenResultingArrayIsNotNull() - { - var sortFunction = new InsertionSortMethods(); - var array = InsertionSortMethods.CreateRandomArray(200); + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsSorted_ThenResultingArrayIsNotNull() + { + var sortFunction = new InsertionSortMethods(); + var array = InsertionSortMethods.CreateRandomArray(200); + + var sortedArray = sortFunction.SortArray(array, array.Length); - var sortedArray = sortFunction.SortArray(array, array.Length, string.Empty); + Assert.IsNotNull(sortedArray); + } - Assert.IsNotNull(sortedArray); - } + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsRandomized_ThenReturnSortedArrayUsingRecursion() + { + 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 InsertionSortMethods(); - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsRandomized_ThenReturnSortedArrayUsingRecursion() - { - 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 InsertionSortMethods(); + var sortedArray = sortFunction.SortArrayRecursive(array, array.Length); - var sortedArray = sortFunction.SortArrayRecursive(array, array.Length, string.Empty); + Assert.IsNotNull(sortedArray); + CollectionAssert.AreEqual(expected, sortedArray); + } - Assert.IsNotNull(sortedArray); - CollectionAssert.AreEqual(sortedArray, expected); - } + [TestMethod] + public void GivenArray_WhenArrayHasSingleElement_ThenReturnSortedArray() + { + var array = new int[] { 73 }; + var expected = new int[] { 73 }; + var sortFunction = new InsertionSortMethods(); - [TestMethod] - public void GivenArray_WhenArrayHasSingleElement_ThenReturnSortedArray() + var sortedArray = sortFunction.SortArray(array, array.Length); + + Assert.IsNotNull(sortedArray); + CollectionAssert.AreEqual(expected, sortedArray); + } + + [TestMethod] + [DataRow("Random")] + [DataRow("Sorted")] + [DataRow("Reversed")] + [DataRow("Duplicates")] + [DataRow("Empty")] + public void GivenInput_WhenSortedWithBothVersions_ThenResultsMatchArraySort(string input) + { + var random = new Random(42); + int[] source = input switch { - var array = new int[] { 73 }; - var expected = new int[] { 73 }; - var sortFunction = new InsertionSortMethods(); + "Sorted" => InsertionSortMethods.CreateSortedArray(500), + "Reversed" => InsertionSortMethods.CreateReversedArray(InsertionSortMethods.CreateSortedArray(500)), + "Duplicates" => Enumerable.Range(0, 500).Select(_ => random.Next(10)).ToArray(), + "Empty" => [], + _ => Enumerable.Range(0, 500).Select(_ => random.Next()).ToArray() + }; + var expected = (int[])source.Clone(); + Array.Sort(expected); + var sortFunction = new InsertionSortMethods(); - var sortedArray = sortFunction.SortArray(array, array.Length, string.Empty); + var imperative = sortFunction.SortArray((int[])source.Clone(), source.Length); + var recursive = sortFunction.SortArrayRecursive((int[])source.Clone(), source.Length); - Assert.IsNotNull(sortedArray); - CollectionAssert.AreEqual(sortedArray, expected); - } + CollectionAssert.AreEqual(expected, imperative); + CollectionAssert.AreEqual(expected, recursive); } -} \ No newline at end of file +}