From 4f1fd03c73d45a477c4898968610efe0199c7fb8 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Sun, 1 Nov 2026 17:36:00 +0100 Subject: [PATCH] QuickSort: net10.0, benchmark copies its input, middle-pivot variant and tests Retarget both projects to net10.0 and update BenchmarkDotNet, MSTest, Test SDK and coverlet. SortArray drops the benchmark-only fourth parameter so it matches the article. The new QuickSortBenchmarks class copies the source array per call so unsorted input stays unsorted, and compares the first-element pivot, a middle-element pivot and Array.Sort at 200, 1000 and 2000 elements. Tests cover the article array, random input against Array.Sort, and 100,000 presorted elements with the middle pivot. --- .../QuickSort/QuickSort/Program.cs | 2 +- .../QuickSort/QuickSort/QuickSort.csproj | 4 +- .../QuickSort/QuickSortBenchmarks.cs | 47 ++++++ .../QuickSort/QuickSort/QuickSortMethods.cs | 140 ++++++++++-------- .../QuickSortTests/QuickSortTests.csproj | 12 +- .../QuickSortTests/QuickSortUnitTests.cs | 77 ++++++---- 6 files changed, 182 insertions(+), 100 deletions(-) create mode 100644 csharp-algorithms/QuickSort/QuickSort/QuickSortBenchmarks.cs diff --git a/csharp-algorithms/QuickSort/QuickSort/Program.cs b/csharp-algorithms/QuickSort/QuickSort/Program.cs index 3ec9c15d23..da43cd640b 100644 --- a/csharp-algorithms/QuickSort/QuickSort/Program.cs +++ b/csharp-algorithms/QuickSort/QuickSort/Program.cs @@ -1,4 +1,4 @@ using BenchmarkDotNet.Running; using QuickSort; -var summary = BenchmarkRunner.Run(); \ No newline at end of file +BenchmarkRunner.Run(args: args); diff --git a/csharp-algorithms/QuickSort/QuickSort/QuickSort.csproj b/csharp-algorithms/QuickSort/QuickSort/QuickSort.csproj index 79e7148fd0..62be4f867f 100644 --- a/csharp-algorithms/QuickSort/QuickSort/QuickSort.csproj +++ b/csharp-algorithms/QuickSort/QuickSort/QuickSort.csproj @@ -2,13 +2,13 @@ Exe - net6.0 + net10.0 enable enable - + diff --git a/csharp-algorithms/QuickSort/QuickSort/QuickSortBenchmarks.cs b/csharp-algorithms/QuickSort/QuickSort/QuickSortBenchmarks.cs new file mode 100644 index 0000000000..90f28e8944 --- /dev/null +++ b/csharp-algorithms/QuickSort/QuickSort/QuickSortBenchmarks.cs @@ -0,0 +1,47 @@ +using BenchmarkDotNet.Attributes; + +namespace QuickSort; + +public class QuickSortBenchmarks +{ + private readonly QuickSortMethods _sorter = new(); + private int[] _source = []; + private int[] _work = []; + + [Params(200, 1000, 2000)] + public int Size { get; set; } + + [Params("Unsorted", "Sorted")] + public string Input { get; set; } = "Unsorted"; + + [GlobalSetup] + public void Setup() + { + _source = Input == "Sorted" + ? QuickSortMethods.CreateSortedArray(Size) + : QuickSortMethods.CreateRandomArray(Size); + _work = new int[Size]; + } + + [Benchmark(Baseline = true)] + public int[] FirstElementPivot() + { + _source.CopyTo(_work, 0); + return _sorter.SortArray(_work, 0, _work.Length - 1); + } + + [Benchmark] + public int[] MiddleElementPivot() + { + _source.CopyTo(_work, 0); + return _sorter.SortArrayWithMiddlePivot(_work, 0, _work.Length - 1); + } + + [Benchmark] + public int[] ArraySort() + { + _source.CopyTo(_work, 0); + Array.Sort(_work); + return _work; + } +} diff --git a/csharp-algorithms/QuickSort/QuickSort/QuickSortMethods.cs b/csharp-algorithms/QuickSort/QuickSort/QuickSortMethods.cs index 23ff55a1ba..ebcb8f4bd0 100644 --- a/csharp-algorithms/QuickSort/QuickSort/QuickSortMethods.cs +++ b/csharp-algorithms/QuickSort/QuickSort/QuickSortMethods.cs @@ -1,76 +1,98 @@ -using BenchmarkDotNet.Attributes; +namespace QuickSort; -namespace QuickSort +public class QuickSortMethods { - public class QuickSortMethods + public int[] SortArray(int[] array, int leftIndex, int rightIndex) { - public IEnumerable SampleArrays() - { - yield return new object[] { CreateRandomArray(200), 0, 199, "Small Unsorted" }; - yield return new object[] { CreateRandomArray(2000), 0, 1999, "Medium Unsorted" }; - yield return new object[] { CreateRandomArray(10000), 0, 9999, "Large Unsorted" }; - yield return new object[] { CreateSortedArray(200), 0, 199, "Small Sorted" }; - yield return new object[] { CreateSortedArray(2000), 0, 1999, "Medium Sorted" }; - yield return new object[] { CreateSortedArray(10000), 0, 9999, "Large Sorted" }; - } - - [Benchmark] - [ArgumentsSource(nameof(SampleArrays))] - public int[] SortArray(int[] array, int leftIndex, int rightIndex, string arrayName) - { - var i = leftIndex; - var j = rightIndex; - var pivot = array[leftIndex]; + var i = leftIndex; + var j = rightIndex; + var pivot = array[leftIndex]; - while (i <= j) + while (i <= j) + { + while (array[i] < pivot) { - while (array[i] < pivot) - { - i++; - } - - while (array[j] > pivot) - { - j--; - } - - if (i <= j) - { - int temp = array[i]; - array[i] = array[j]; - array[j] = temp; - i++; - j--; - } + i++; } - - if (leftIndex < j) - SortArray(array, leftIndex, j, arrayName); - if (i < rightIndex) - SortArray(array, i, rightIndex, arrayName); + while (array[j] > pivot) + { + j--; + } - return array; + if (i <= j) + { + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + i++; + j--; + } } - - 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(); + if (leftIndex < j) + SortArray(array, leftIndex, j); - return array; - } - public static int[] CreateSortedArray(int size) + if (i < rightIndex) + SortArray(array, i, rightIndex); + + return array; + } + + public int[] SortArrayWithMiddlePivot(int[] array, int leftIndex, int rightIndex) + { + var i = leftIndex; + var j = rightIndex; + var pivot = array[leftIndex + (rightIndex - leftIndex) / 2]; + + while (i <= j) { - var array = new int[size]; + while (array[i] < pivot) + { + i++; + } - for (int i = 0; i < size; i++) - array[i] = i; + while (array[j] > pivot) + { + j--; + } - return array; + if (i <= j) + { + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + i++; + j--; + } } + + if (leftIndex < j) + SortArrayWithMiddlePivot(array, leftIndex, j); + + if (i < rightIndex) + SortArrayWithMiddlePivot(array, i, rightIndex); + + return array; + } + + public static int[] CreateRandomArray(int size) + { + var array = new int[size]; + + for (int i = 0; i < size; i++) + array[i] = Random.Shared.Next(); + + 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; } } diff --git a/csharp-algorithms/QuickSort/QuickSortTests/QuickSortTests.csproj b/csharp-algorithms/QuickSort/QuickSortTests/QuickSortTests.csproj index 7c8ee2948f..c456bbc45a 100644 --- a/csharp-algorithms/QuickSort/QuickSortTests/QuickSortTests.csproj +++ b/csharp-algorithms/QuickSort/QuickSortTests/QuickSortTests.csproj @@ -1,17 +1,17 @@ - net6.0 + net10.0 + enable enable - false - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/csharp-algorithms/QuickSort/QuickSortTests/QuickSortUnitTests.cs b/csharp-algorithms/QuickSort/QuickSortTests/QuickSortUnitTests.cs index bd01498534..dea8c7cd75 100644 --- a/csharp-algorithms/QuickSort/QuickSortTests/QuickSortUnitTests.cs +++ b/csharp-algorithms/QuickSort/QuickSortTests/QuickSortUnitTests.cs @@ -1,46 +1,59 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using QuickSort; -using System; -namespace QuickSortTests +namespace QuickSortTests; + +[TestClass] +public class QuickSortUnitTests { - [TestClass] - public class QuickSortUnitTests + [TestMethod] + public void GivenUnsortedArray_WhenArrayIsNotEmpty_ThenReturnSortedArray() { - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsNotEmpty_ThenReturnSortedArray() - { - var array = new int[] { 73, 57, 49, 99, 133, 20, 1, 73, 57, 49, 99, 133, 20, 1 }; - var expected = new int[] { 1, 1,20, 20, 49, 49, 57, 57, 73, 73, 99, 99, 133, 133 }; - - var sortFunction = new QuickSortMethods(); + var array = new int[] { 73, 57, 49, 99, 133, 20, 1, 73, 57, 49, 99, 133, 20, 1 }; + var expected = new int[] { 1, 1, 20, 20, 49, 49, 57, 57, 73, 73, 99, 99, 133, 133 }; + + var sortFunction = new QuickSortMethods(); - var sortedArray = sortFunction.SortArray(array, 0, array.Length - 1, string.Empty); + var sortedArray = sortFunction.SortArray(array, 0, array.Length - 1); - Assert.IsNotNull(sortedArray); - CollectionAssert.AreEqual(sortedArray, expected); - } + Assert.IsNotNull(sortedArray); + CollectionAssert.AreEqual(expected, sortedArray); + } - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsNotEmpty_ThenCheckInstanceType() - { - var sortFunction = new QuickSortMethods(); - var array = QuickSortMethods.CreateRandomArray(200); + [TestMethod] + public void GivenArticleArray_WhenSorted_ThenAllNineElementsAreInOrder() + { + int[] array = { 52, 96, 67, 71, 42, 38, 39, 40, 14 }; + var expected = new int[] { 14, 38, 39, 40, 42, 52, 67, 71, 96 }; - var sortedArray = sortFunction.SortArray(array, 0, array.Length - 1, string.Empty); + var sortedArray = new QuickSortMethods().SortArray(array, 0, array.Length - 1); - Assert.IsInstanceOfType(sortedArray, typeof(int[])); - } + CollectionAssert.AreEqual(expected, sortedArray); + } - [TestMethod] - public void GivenUnsortedArray_WhenArrayIsSorted_ThenResultingArrayIsNotNull() - { - var sortFunction = new QuickSortMethods(); - var array = QuickSortMethods.CreateRandomArray(5); + [TestMethod] + public void GivenRandomArray_WhenSortedWithEitherPivot_ThenMatchesArraySort() + { + var sortFunction = new QuickSortMethods(); + var source = QuickSortMethods.CreateRandomArray(2000); + var expected = (int[])source.Clone(); + Array.Sort(expected); + + var firstPivot = sortFunction.SortArray((int[])source.Clone(), 0, source.Length - 1); + var middlePivot = sortFunction.SortArrayWithMiddlePivot((int[])source.Clone(), 0, source.Length - 1); + + CollectionAssert.AreEqual(expected, firstPivot); + CollectionAssert.AreEqual(expected, middlePivot); + } + + [TestMethod] + public void GivenSortedArray_WhenSortedWithMiddlePivot_ThenStaysSorted() + { + var array = QuickSortMethods.CreateSortedArray(100_000); + var expected = QuickSortMethods.CreateSortedArray(100_000); - var sortedArray = sortFunction.SortArray(array, 0, array.Length - 1, string.Empty); + var sortedArray = new QuickSortMethods().SortArrayWithMiddlePivot(array, 0, array.Length - 1); - Assert.IsNotNull(sortedArray); - } + CollectionAssert.AreEqual(expected, sortedArray); } -} \ No newline at end of file +}